Compare commits
477 Commits
master
...
sysmocom/m
Author | SHA1 | Date |
---|---|---|
Asterisk Development Team | af5acc405d | |
Asterisk Development Team | 9b6c74e82a | |
George Joseph | d7597e5148 | |
Asterisk Development Team | 959babc472 | |
Naveen Albert | 40fd161575 | |
Naveen Albert | 5ade71ec9a | |
Shaaah | 395bcab787 | |
Naveen Albert | 3469e515de | |
Sean Bright | f8da5a2ba3 | |
George Joseph | f02ac33364 | |
George Joseph | 44563b5043 | |
George Joseph | efc2124594 | |
George Joseph | be5fd6180c | |
George Joseph | fd27df9479 | |
Sean Bright | 507c28f268 | |
Sebastian Jennen | 77808edbd4 | |
Shyju Kanaprath | 2868366f00 | |
Sean Bright | 02a17926c4 | |
George Joseph | 4152f67a0b | |
George Joseph | 41ae2d754f | |
romryz | a494b61fe2 | |
Naveen Albert | 70ff49c474 | |
George Joseph | f770c9c92c | |
George Joseph | 6df5fbee65 | |
Naveen Albert | bf6a367955 | |
Ben Ford | ab2163cacb | |
cmaj | db99ad892b | |
Joshua C. Colp | ba68bb9221 | |
Mike Bradeen | ec69680801 | |
George Joseph | 36fd2ac5b6 | |
Naveen Albert | e2cb63120f | |
Sean Bright | f74eafcf65 | |
Brad Smith | 17757f76fe | |
Brad Smith | afe0fb310d | |
Sean Bright | 4d09fb191c | |
Sean Bright | 347494a130 | |
Naveen Albert | faf4c3b5d3 | |
Naveen Albert | 309ec5e762 | |
Sean Bright | 61c78fc48b | |
Mike Bradeen | 9652a215e8 | |
Naveen Albert | e17c4e172f | |
PeterHolik | 9943bc5f1f | |
PeterHolik | 07715c4c27 | |
Naveen Albert | 410909fbfb | |
Asterisk Development Team | b05169bcac | |
Asterisk Development Team | f258d08bac | |
Naveen Albert | 87fb29020b | |
Asterisk Development Team | 3ba0470953 | |
George Joseph | a42c5438e9 | |
Naveen Albert | fd57ddb3e9 | |
Maximilian Fridrich | b2eb25a88c | |
Naveen Albert | d7948f5425 | |
Naveen Albert | c6b82b19a4 | |
Naveen Albert | 8a73bac226 | |
Naveen Albert | 776c2ca6d7 | |
Sean Bright | cfe826791e | |
Naveen Albert | 91127a618f | |
George Joseph | 98a44b95df | |
Maximilian Fridrich | 8f9200d106 | |
George Joseph | 9ae72b0a23 | |
Sean Bright | 2c6385a1b3 | |
Matthew Fredrickson | 37a89d3cee | |
Sean Bright | 5988da4ec5 | |
Sean Bright | 2f7416711e | |
Sean Bright | 3ed329edc9 | |
Sean Bright | 06d86c41af | |
Naveen Albert | 7279d7547f | |
Sean Bright | d52c427533 | |
Sean Bright | b7e66d49b2 | |
Naveen Albert | a6d856aba2 | |
Sean Bright | f19b74ad31 | |
Sean Bright | 989e61890a | |
Sean Bright | 69a19aabd8 | |
Sean Bright | fe92d09361 | |
Sean Bright | eb48273bdf | |
George Joseph | 3127baec78 | |
Naveen Albert | 4d928ee975 | |
Matthew Fredrickson | eac9ad69a8 | |
Naveen Albert | 52388f11f8 | |
Naveen Albert | 0007625ad0 | |
Sean Bright | c2680f63c5 | |
George Joseph | 1d87c27cab | |
Sean Bright | da35b6a244 | |
Sean Bright | fb7d39db6d | |
George Joseph | 94f931a6d7 | |
Sean Bright | f96d7ef7b5 | |
Naveen Albert | e75aebc9bc | |
Holger Hans Peter Freyther | 7699af00e1 | |
Holger Hans Peter Freyther | 28f52d35f3 | |
Brad Smith | 089ddaaaed | |
Brad Smith | fb3067dd71 | |
Naveen Albert | 6a4fe8bdab | |
Naveen Albert | b47a403b80 | |
Mark Murawski | 3b70dfcced | |
Naveen Albert | b5eb5e19c3 | |
Sean Bright | 3ded0c95fc | |
George Joseph | e2f246c067 | |
Naveen Albert | 120dbba2b3 | |
Mike Bradeen | 0b4427d621 | |
Sean Bright | ea74f942ce | |
Sean Bright | 58f78d2d0e | |
George Joseph | 027c748e57 | |
Sean Bright | 93697458a6 | |
Samuel Olaechea | 59181860ec | |
George Joseph | e52175341e | |
sungtae kim | faf046ea86 | |
George Joseph | 95656c409d | |
George Joseph | 13f2d126fd | |
George Joseph | 2cb140f801 | |
Mike Bradeen | 0f2eb00a52 | |
Holger Hans Peter Freyther | 1f7e9bfad5 | |
Sean Bright | d7a01afa50 | |
George Joseph | fd487b48a3 | |
George Joseph | e1ce35c3f5 | |
Joshua C. Colp | b7cc7e804b | |
George Joseph | f0edab9f3e | |
George Joseph | 393d8cb947 | |
Mike Bradeen | 0df2848147 | |
Naveen Albert | c06fd10f0a | |
Bastian Triller | 7a1208410a | |
Mike Bradeen | c47a386cf2 | |
Naveen Albert | 0a834c8d75 | |
Eduardo | 7a2305a08b | |
George Joseph | 9afa54b3b3 | |
George Joseph | 97674e1d20 | |
Tinet-mucw | a86376fe68 | |
Mike Bradeen | 3b61583c20 | |
Naveen Albert | 3fef46e776 | |
George Joseph | d5a285c8f2 | |
Naveen Albert | accedd4c3e | |
Vitezslav Novy | c275ee9e54 | |
George Joseph | 172602d30e | |
Mike Bradeen | 58a37523dd | |
Sean Bright | d9dc7b66e4 | |
Mike Bradeen | b68370ba9c | |
George Joseph | 9ee35c259a | |
George Joseph | 52929efb83 | |
Maximilian Fridrich | 38598701da | |
Jaco Kroon | bc72c76891 | |
Joshua C. Colp | 6521066fbe | |
George Joseph | c2d3ad489d | |
Asterisk Development Team | 4988f9131f | |
George Joseph | 32b57067a6 | |
Asterisk Development Team | f7a8ac086d | |
Gitea | b6122db51d | |
Mike Bradeen | 48e435f84f | |
George Joseph | e46cc258ab | |
Ben Ford | d44f07244a | |
Asterisk Development Team | c94e2b2000 | |
Asterisk Development Team | a2fb6d4dd4 | |
George Joseph | f7fd2c8e20 | |
George Joseph | 1d9ea90058 | |
George Joseph | e5a653622a | |
Bastian Triller | 9d41064bc0 | |
George Joseph | abc84c6618 | |
Naveen Albert | 7959c64792 | |
Mike Bradeen | 7353462be3 | |
George Joseph | 4dcf73b6df | |
Naveen Albert | 2d1e4aed4f | |
zhengsh | 6ef2389e9b | |
George Joseph | c3f4b56886 | |
Maximilian Fridrich | b2cd0583c9 | |
Naveen Albert | 534269e3e6 | |
Matthew Fredrickson | 8bf9b1d966 | |
Matthew Fredrickson | 65082ae112 | |
George Joseph | b145430957 | |
Jason D. McCormick | f86f5fd809 | |
MikeNaso | 714b9e8b21 | |
Sean Bright | cce02a9d60 | |
George Joseph | 44d7349958 | |
Naveen Albert | 9367926380 | |
George Joseph | 5e3652e738 | |
Joshua C. Colp | 592c85b8de | |
Maximilian Fridrich | 68fc422247 | |
Naveen Albert | 65a2bca074 | |
Joshua C. Colp | fcf7187cd6 | |
Naveen Albert | 18aa912f46 | |
Holger Hans Peter Freyther | 986c71953c | |
Sean Bright | e05f51a8ae | |
phoneben | cbcde0624b | |
Sean Bright | 4ed17ced6c | |
Sean Bright | 29fbf1b2c8 | |
Joshua C. Colp | ef7a9e91fe | |
George Joseph | c0898cb265 | |
Sean Bright | 22f31ecedd | |
Sean Bright | db8601dd77 | |
Mike Bradeen | dd76dfdd57 | |
Mike Bradeen | d9c4a37aaa | |
zhengsh | 37b1ceab2b | |
George Joseph | 5cf2c9f0e4 | |
George Joseph | e33e6c6429 | |
Naveen Albert | 967e8f6beb | |
Asterisk Development Team | 9e2b9424f5 | |
Asterisk Development Team | 3a0d24d969 | |
George Joseph | 6cfafdeb37 | |
George Joseph | 9b3abda528 | |
Asterisk Development Team | c35471ad10 | |
George Joseph | 1491da61eb | |
Mike Bradeen | d180c58c36 | |
Mike Bradeen | 9dbd80ab73 | |
Mike Bradeen | 714950bd7c | |
George Joseph | 244e0b69ea | |
George Joseph | 37d2378073 | |
George Joseph | 46bb9e8fde | |
George Joseph | 64ecad8309 | |
George Joseph | f6630916f4 | |
George Joseph | 157d478b27 | |
George Joseph | 8a152fb4aa | |
George Joseph | 37dce12781 | |
George Joseph | fdfe61bf4d | |
Olaf Titz | f7f2872b3f | |
Sean Bright | 81b490ab0a | |
Ben Ford | ff4f3c1187 | |
Nathan Bruning | f0df2eba9d | |
Sean Bright | ff60aae1c8 | |
Sean Bright | 99622c35e0 | |
Sean Bright | 5497b1abe3 | |
zhou_jiajian | 3ad8ab6d52 | |
Sean Bright | f971db6685 | |
George Joseph | 8e6f15d185 | |
Sean Bright | 0503e2b612 | |
Jaco Kroon | dafa9917ff | |
Jiajian Zhou | a6a5498b0d | |
George Joseph | b7775ae4e1 | |
George Joseph | ee09bbbb5f | |
George Joseph | 40ff67d636 | |
Sean Bright | 79d271fa7f | |
alex2grad | 319da11fae | |
Sean Bright | 228244a96e | |
Miguel Angel Nubla | 25de041d5e | |
Naveen Albert | 8cdf711531 | |
Naveen Albert | 457a72304d | |
Ben Ford | 8da7b4606b | |
Naveen Albert | f40e50ce19 | |
Joe Searle | 5018c09d99 | |
Niklas Larsson | 1589efa5dd | |
George Joseph | b68bf5683f | |
Mike Bradeen | 26401ddcc0 | |
George Joseph | da66f402c9 | |
George Joseph | 75c13b2c95 | |
Naveen Albert | ba1c363d3e | |
Naveen Albert | c8b7570cad | |
Maximilian Fridrich | 173c433274 | |
Naveen Albert | c5c89ed377 | |
George Joseph | 0d214b6611 | |
Naveen Albert | ca51a25056 | |
George Joseph | cd2eafe588 | |
George Joseph | 955c2e06ff | |
George Joseph | 5e37887d82 | |
Jaco Kroon | dda4dd513f | |
Sean Bright | bbf47fefab | |
zhengsh | 2d1e5f81ee | |
Sean Bright | 0e4a9d7251 | |
Joshua C. Colp | 6812357bef | |
Gitea | d35a0d3d4e | |
Joshua C. Colp | 31c11bec74 | |
Asterisk Development Team | 6dc1877b2d | |
Sean Bright | 9ca24c9c2b | |
George Joseph | 90069a94b0 | |
Stanislav Abramenkov | 0fa022a39c | |
Asterisk Development Team | 282045db34 | |
George Joseph | a004574465 | |
Asterisk Development Team | 2e1842229a | |
George Joseph | 3fe0d8088f | |
Henning Westerholt | ac747ce562 | |
Mike Bradeen | 21ee5f705a | |
Sean Bright | 7677e78b4f | |
George Joseph | 9a1ac9142f | |
George Joseph | 272fbca4d0 | |
George Joseph | e3b9f66678 | |
George Joseph | 6aa490d373 | |
Maximilian Fridrich | 9cfda39d36 | |
George Joseph | ea564b640d | |
Joshua C. Colp | 42c243866e | |
Naveen Albert | e6b84eca75 | |
George Joseph | 81310a031c | |
George Joseph | 5cb6d8a453 | |
George Joseph | cc36ae8de5 | |
George Joseph | f994463aee | |
Joshua C. Colp | 6a347f413d | |
Joshua Colp | 9c5f5358d7 | |
Naveen Albert | 59c9e4531e | |
Naveen Albert | 99d17db963 | |
The_Blode | 81a912f3ce | |
Henning Westerholt | 51509309ca | |
Naveen Albert | c9aa3b0169 | |
Naveen Albert | 5e7d21e5a5 | |
George Joseph | d0ce6d4ee5 | |
Jaco Kroon | 3a158c07a1 | |
Sean Bright | 255565e240 | |
Sean Bright | 6ff3258c17 | |
Mike Bradeen | 2ac8388c6d | |
Mike Bradeen | e00eaa74e3 | |
Mike Bradeen | 3a4fd2fa42 | |
Sean Bright | b376d16d81 | |
Naveen Albert | e104bd0852 | |
Naveen Albert | 3dcf6ddde5 | |
Naveen Albert | 0dd0bc3e65 | |
Fabrice Fontaine | bdd2bac055 | |
Mike Bradeen | 5a85b372af | |
Jaco Kroon | d6e733d4bc | |
George Joseph | bd1f8b89da | |
Holger Hans Peter Freyther | 723c9093ad | |
Fabrice Fontaine | b17177c419 | |
Sean Bright | 61c8f9b225 | |
Asterisk Development Team | 1d64cb99d2 | |
Mike Bradeen | f8dfbaf225 | |
Sean Bright | 6e50550d28 | |
Asterisk Development Team | e7f0440032 | |
Asterisk Development Team | 460d13e916 | |
Asterisk Development Team | 93813c9dca | |
George Joseph | ceda5a9859 | |
Sean Bright | e5c5cd6e25 | |
Naveen Albert | ede67a99be | |
Sean Bright | 827222d607 | |
Nick French | 200dc7d0e8 | |
Mike Bradeen | 5c11d7adea | |
cmaj | 5b0e3444c3 | |
Mike Bradeen | 2308afed8e | |
Mike Bradeen | 98742388b6 | |
Mike Bradeen | 37e558f6ef | |
Sean Bright | aeb16aa7d8 | |
Sean Bright | aef0c0ce0e | |
Mike Bradeen | 58636a6ea6 | |
Sean Bright | 96d9ad51ac | |
Naveen Albert | 88b2c741ca | |
Mike Bradeen | 70856e865f | |
Naveen Albert | 8a45cd7af4 | |
sungtae kim | f99849f8d5 | |
Sean Bright | 56051d1ac5 | |
Naveen Albert | a1da8042d1 | |
Sean Bright | ef16eaee36 | |
George Joseph | 2f5aece0c9 | |
Alexei Gradinari | e86d5d7fda | |
Igor Goncharovsky | 3526441e41 | |
George Joseph | 4710f37ef6 | |
George Joseph | 62ca063fca | |
Naveen Albert | d33bd6d67a | |
Naveen Albert | e06fe8e344 | |
Naveen Albert | 68e345286b | |
Naveen Albert | 3b3fef2347 | |
Naveen Albert | 7b8f7428da | |
George Joseph | 24102ba236 | |
Boris P. Korzun | edc90c96ac | |
Holger Hans Peter Freyther | 3d9b9a2b16 | |
George Joseph | d454801c2d | |
Naveen Albert | cc8d9b947b | |
Naveen Albert | c7598ee947 | |
Ben Ford | 881faf544f | |
Naveen Albert | 20d4775d0a | |
Naveen Albert | cbb1fd2cb9 | |
Igor Goncharovsky | 115a1b4f0a | |
Peter Fern | 58404b5c22 | |
Naveen Albert | 36bea9ad33 | |
Asterisk Development Team | fefc236e7c | |
Alexandre Fournier | 01b3962201 | |
Joshua C. Colp | b6855755ce | |
Naveen Albert | 2f9cdfbc50 | |
Michael Kuron | 5c114dcb4a | |
Michael Kuron | fee9012fe1 | |
Joshua C. Colp | 564349ff5d | |
Naveen Albert | b9c031c1f8 | |
Marcel Wagner | 58534b309f | |
Naveen Albert | 531eacd6c9 | |
Naveen Albert | b365ea8601 | |
Naveen Albert | 0d6003fa9a | |
Marcel Wagner | b83af13f65 | |
Naveen Albert | 80e6205bb0 | |
Naveen Albert | 406143ae61 | |
Naveen Albert | 83eb113e0f | |
Naveen Albert | b90e57758b | |
Naveen Albert | 52c7d3ed07 | |
Naveen Albert | a4bcdce1db | |
Naveen Albert | 691178c48e | |
Ben Ford | d476994768 | |
George Joseph | 7684c9e907 | |
Mike Bradeen | 81f10e847e | |
Mike Bradeen | eb1d7ab53c | |
Naveen Albert | c7df5ee7c1 | |
Naveen Albert | 5ede4e217a | |
Maximilian Fridrich | 60b81eabe0 | |
Naveen Albert | 2efa290d3c | |
Jaco Kroon | ce2153fc5a | |
Naveen Albert | 002afc3f2a | |
Naveen Albert | 1e77b8c473 | |
Joshua C. Colp | 61922d2934 | |
Naveen Albert | 6e59b01e1a | |
Naveen Albert | 49cfdbbdff | |
Naveen Albert | 8142b313c3 | |
George Joseph | 0c1c623dee | |
Naveen Albert | dfe2f38642 | |
George Joseph | f723b465e5 | |
Mike Bradeen | 50e2921a48 | |
Naveen Albert | afd86b47c1 | |
Igor Goncharovsky | 096529d33f | |
Naveen Albert | ca8900b0f6 | |
Henning Westerholt | 12445040d3 | |
Naveen Albert | 40b52322e5 | |
Naveen Albert | c32b39d123 | |
Frederic LE FOLL | 50a4495799 | |
Naveen Albert | 180ca32565 | |
Naveen Albert | 9258d8212a | |
Naveen Albert | 407216a0a5 | |
Philip Prindeville | d0bea5a725 | |
Mike Bradeen | 907d7e7d7d | |
Naveen Albert | b331caca30 | |
Naveen Albert | e0e7f35730 | |
Naveen Albert | 98fc05f13b | |
Philip Prindeville | ef74ecacc7 | |
Philip Prindeville | 5e2485b5c0 | |
George Joseph | 2a500b325a | |
Maximilian Fridrich | 0d2e140123 | |
Asterisk Development Team | 7f80830ced | |
Holger Hans Peter Freyther | 62881c668b | |
Naveen Albert | 8afb313a43 | |
Naveen Albert | 7335b0cffe | |
Naveen Albert | 407167cc28 | |
Naveen Albert | a5ec60e6c6 | |
Naveen Albert | 1e29607b5c | |
Naveen Albert | 8c791f9a65 | |
Philip Prindeville | 3e7ce90f9c | |
Naveen Albert | 1ed4518328 | |
Maximilian Fridrich | 5bbad0d27c | |
Naveen Albert | 8aae0b9f08 | |
Jaco Kroon | 278c5726ca | |
Naveen Albert | ab1dbfef75 | |
George Joseph | e25b690d10 | |
George Joseph | e33f2dcc0f | |
Philip Prindeville | 026dc08529 | |
Asterisk Development Team | f01ed3eea4 | |
Mike Bradeen | 7a44296ca9 | |
George Joseph | 8cbea1c7ef | |
sungtae kim | 80bc844fd6 | |
Ben Ford | 881a3f2306 | |
Philip Prindeville | 3e054c9ebc | |
Philip Prindeville | 736cdf84f4 | |
Philip Prindeville | 2d7656cb50 | |
Philip Prindeville | 5809d879b0 | |
Philip Prindeville | 2c4c44ca64 | |
Philip Prindeville | b9df2c481b | |
Philip Prindeville | d13afaf302 | |
Naveen Albert | 2dac2bf8dc | |
Naveen Albert | c487425620 | |
Naveen Albert | 205c7c8d21 | |
Naveen Albert | 2de016b181 | |
George Joseph | 05f42806cc | |
George Joseph | c799db6a21 | |
George Joseph | 4ffc5561c4 | |
George Joseph | 2d5a6498dd | |
Joshua C. Colp | f3de933b16 | |
Naveen Albert | c7612521be | |
Joshua C. Colp | a0713a9f70 | |
Naveen Albert | 754346a4a9 | |
Mike Bradeen | 46776c77c4 | |
Sean Bright | 583e017f34 | |
Alexei Gradinari | 12c4c1bf5f | |
Sean Bright | 155c796203 | |
Naveen Albert | 3fa66c92b5 | |
Mike Bradeen | adffb975dc | |
Mike Bradeen | 4fc9e06db1 | |
Naveen Albert | e2e049e473 | |
George Joseph | 8a8416e365 | |
Naveen Albert | ff044c222b | |
Naveen Albert | dc7ec11c26 | |
George Joseph | 30d7a212b0 | |
Naveen Albert | f4a020a45b | |
Naveen Albert | c654486547 | |
Naveen Albert | 5feebc0857 | |
Naveen Albert | 165368bf0b | |
Naveen Albert | 2d8f2696b2 | |
Naveen Albert | 4af881506e | |
Naveen Albert | 83912496ab | |
Naveen Albert | c771e2dd7a | |
Sergey V. Lobanov | f645157a4b | |
Naveen Albert | a9223f210e | |
Naveen Albert | ce18196280 | |
George Joseph | f8000daff5 |
|
@ -0,0 +1,87 @@
|
|||
name: Bug
|
||||
description: File a bug report
|
||||
title: "[bug]: "
|
||||
labels: ["bug", "triage"]
|
||||
#assignees:
|
||||
# - octocat
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: dropdown
|
||||
id: severity
|
||||
attributes:
|
||||
label: Severity
|
||||
options:
|
||||
- Trivial
|
||||
- Minor
|
||||
- Major
|
||||
- Critical
|
||||
- Blocker
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: versions
|
||||
attributes:
|
||||
label: Versions
|
||||
description: Enter one or more versions separated by commas.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: components
|
||||
attributes:
|
||||
label: Components/Modules
|
||||
description: Enter one or more components or modules separated by commas.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Operating Environment
|
||||
description: OS, Disribution, Version, etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: frequency
|
||||
attributes:
|
||||
label: Frequency of Occurrence
|
||||
options:
|
||||
- "Never"
|
||||
- "One Time"
|
||||
- "Occasional"
|
||||
- "Frequent"
|
||||
- "Constant"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Issue Description
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
[Asterisk Issue Guidelines](https://wiki.asterisk.org/wiki/display/AST/Asterisk+Issue+Guidelines)
|
||||
- type: checkboxes
|
||||
id: guidelines
|
||||
attributes:
|
||||
label: Asterisk Issue Guidelines
|
||||
options:
|
||||
- label: Yes, I have read the Asterisk Issue Guidelines
|
||||
required: true
|
|
@ -0,0 +1,11 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Asterisk Community Support
|
||||
url: https://community.asterisk.org
|
||||
about: Please ask and answer questions here.
|
||||
- name: Feature Requests (Without Code)
|
||||
url: https://github.com/asterisk/asterisk-feature-requests/issues
|
||||
about: Please submit feature requests (without code) here.
|
||||
- name: Improvement Requests (Without Code)
|
||||
url: https://github.com/asterisk/asterisk-feature-requests/issues
|
||||
about: Please submit improvement requests (without code) here.
|
|
@ -0,0 +1,27 @@
|
|||
name: Improvement
|
||||
description: Submit an improvement to existing functionality
|
||||
title: "[improvement]: "
|
||||
labels: ["improvement", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Improvement Description
|
||||
description: Describe the improvement in as much detail as possible
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
name: New Feature Submission
|
||||
description: Submit a New Feature
|
||||
title: "[new-feature]: "
|
||||
labels: ["new-feature", "triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for creating a report! The issue has entered the triage process. That means the issue will wait in this status until a Bug Marshal has an opportunity to review the issue. Once the issue has been reviewed you will receive comments regarding the next steps towards resolution. Please note that log messages and other files should not be sent to the Sangoma Asterisk Team unless explicitly asked for. All files should be placed on this issue in a sanitized fashion as needed.
|
||||
|
||||
A good first step is for you to review the Asterisk Issue Guidelines if you haven't already. The guidelines detail what is expected from an Asterisk issue report.
|
||||
|
||||
Then, if you are submitting a patch, please review the Patch Contribution Process.
|
||||
|
||||
Please note that once your issue enters an open state it has been accepted. As Asterisk is an open source project there is no guarantee or timeframe on when your issue will be looked into. If you need expedient resolution you will need to find and pay a suitable developer. Asking for an update on your issue will not yield any progress on it and will not result in a response. All updates are posted to the issue when they occur.
|
||||
|
||||
Please note that by submitting data, code, or documentation to Sangoma through GitHub, you accept the Terms of Use present at
|
||||
https://www.asterisk.org/terms-of-use/.
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Feature Description
|
||||
description: Describe the new feature in as much detail as possible
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
name: CherryPickTest
|
||||
run-name: "Cherry-Pick Tests for PR ${{github.event.number}}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ labeled ]
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
IdentifyBranches:
|
||||
name: IdentifyBranches
|
||||
if: ${{ github.event.label.name == vars.CHERRY_PICK_TEST_LABEL }}
|
||||
outputs:
|
||||
branches: ${{ steps.getbranches.outputs.branches }}
|
||||
branch_count: ${{ steps.getbranches.outputs.branch_count }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Remove Trigger Label, Add InProgress Label
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TEST_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_CHECKS_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_GATES_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_GATES_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
id: getbranches
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Check Branch Count
|
||||
if: ${{ steps.getbranches.outputs.branch_count > 0 }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
CherryPickUnitTestMatrix:
|
||||
needs: [ IdentifyBranches ]
|
||||
if: ${{ needs.IdentifyBranches.outputs.branch_count > 0 && ( success() || failure() ) }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.branches) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Unit Tests for branch ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
unittest_command: ${{vars.UNITTEST_COMMAND}}
|
||||
|
||||
CherryPickUnitTests:
|
||||
needs: [ IdentifyBranches, CherryPickUnitTestMatrix ]
|
||||
if: ${{ needs.IdentifyBranches.outputs.branch_count > 0 && ( success() || failure() ) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check unit test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.CherryPickUnitTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::Unit tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.CHERRY_PICK_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
CherryPickGateTestMatrix:
|
||||
needs: [ IdentifyBranches, CherryPickUnitTests ]
|
||||
if: ${{ success() }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.branches) }}
|
||||
group: ${{ fromJSON(vars.GATETEST_LIST) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Gate Tests for ${{ matrix.group }}-${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Gate
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
testsuite_repo: ${{vars.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{ toJSON(fromJSON(vars.GATETEST_COMMANDS)[matrix.group]) }}
|
||||
|
||||
CherryPickGateTests:
|
||||
needs: [ IdentifyBranches, CherryPickGateTestMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.CherryPickGateTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.CHERRY_PICK_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_GATES_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All Testsuite tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Testsuite tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.CHERRY_PICK_GATES_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more Testsuite tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,123 @@
|
|||
name: CreateDocs
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branches:
|
||||
description: "JSON array of branches: ['18','20'] (no spaces)"
|
||||
required: false
|
||||
type: string
|
||||
schedule:
|
||||
# Times are UTC
|
||||
- cron: '0 04 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DEFAULT_BRANCHES: ${{ vars.WIKIDOC_BRANCHES }}
|
||||
INPUT_BRANCHES: ${{ inputs.branches }}
|
||||
|
||||
jobs:
|
||||
|
||||
CreateDocsDebug:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
manual_branches: ${{ steps.setup.outputs.manual_branches }}
|
||||
steps:
|
||||
- name: setup
|
||||
run: |
|
||||
MANUAL_BRANCHES="$INPUT_BRANCHES"
|
||||
[ -z "$MANUAL_BRANCHES" ] && MANUAL_BRANCHES="$DEFAULT_BRANCHES" || :
|
||||
echo "manual_branches=${MANUAL_BRANCHES}"
|
||||
echo "manual_branches=${MANUAL_BRANCHES}" >>${GITHUB_OUTPUT}
|
||||
exit 0
|
||||
|
||||
- name: DumpEnvironment
|
||||
uses: asterisk/asterisk-ci-actions/DumpEnvironmentAction@main
|
||||
with:
|
||||
action-inputs: ${{toJSON(inputs)}}
|
||||
action-vars: ${{ toJSON(steps.setup.outputs) }}
|
||||
|
||||
CreateDocsScheduledMatrix:
|
||||
needs: [ CreateDocsDebug ]
|
||||
if: ${{github.event_name == 'schedule' && fromJSON(vars.WIKIDOCS_ENABLE) == true }}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.WIKIDOC_BRANCHES) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: CreateDocs for ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/CreateAsteriskDocsComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
docs_dir: docs_dir/${{matrix.branch}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
CreateDocsScheduled:
|
||||
needs: [ CreateDocsScheduledMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check CreateDocsScheduledMatrix status
|
||||
env:
|
||||
RESULT: ${{needs.CreateDocsScheduledMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::Docs created"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::notice::Skipped"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or CreateDocs failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
CreateDocsManualMatrix:
|
||||
needs: [ CreateDocsDebug ]
|
||||
if: ${{github.event_name == 'workflow_dispatch'}}
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.WIKIDOC_MANUAL_BRANCHES) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: CreateDocs for ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/CreateAsteriskDocsComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
docs_dir: docs_dir/${{matrix.branch}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
CreateDocsManual:
|
||||
needs: [ CreateDocsManualMatrix ]
|
||||
if: ${{ success() || failure() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check CreateDocsManualMatrix status
|
||||
env:
|
||||
RESULT: ${{needs.CreateDocsManualMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::Docs created"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::notice::Skipped"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or CreateDocs failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,15 @@
|
|||
name: Issue Opened
|
||||
run-name: "Issue ${{github.event.number}} ${{github.event.action}} by ${{github.actor}}"
|
||||
on:
|
||||
issues:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: initial labeling
|
||||
uses: andymckay/labeler@master
|
||||
with:
|
||||
add-labels: "triage"
|
||||
ignore-if-labeled: true
|
|
@ -0,0 +1,187 @@
|
|||
name: MergeApproved
|
||||
run-name: "Merge Approved for PR ${{github.event.number}}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
BASE_BRANCH: ${{github.event.pull_request.base.ref}}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
FORCE: ${{ endsWith(github.event.label.name, '-force') }}
|
||||
|
||||
jobs:
|
||||
IdentifyBranches:
|
||||
if: contains(fromJSON(vars.MERGE_APPROVED_LABELS), github.event.label.name)
|
||||
outputs:
|
||||
branches: ${{ steps.getbranches.outputs.branches }}
|
||||
all_branches: ${{ steps.checkbranches.outputs.all_branches }}
|
||||
branch_count: ${{ steps.getbranches.outputs.branch_count }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clean up labels
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{github.event.label.name}} \
|
||||
--remove-label ${{vars.PRE_MERGE_CHECKS_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_GATES_PASSED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_GATES_FAILED_LABEL}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
id: getbranches
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Check Branch Count
|
||||
id: checkbranches
|
||||
env:
|
||||
BRANCH_COUNT: ${{ steps.getbranches.outputs.branch_count }}
|
||||
BRANCHES: ${{ steps.getbranches.outputs.branches }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
all_branches=$(echo "$BRANCHES" | jq -c "[ \"$BASE_BRANCH\" ] + .")
|
||||
echo "all_branches=${all_branches}" >>${GITHUB_OUTPUT}
|
||||
|
||||
- name: Pre Check Cherry-Picks
|
||||
if: ${{ steps.getbranches.outputs.branch_count > 0 }}
|
||||
uses: asterisk/asterisk-ci-actions/CherryPick@main
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
branches: ${{steps.getbranches.outputs.branches}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
push: false
|
||||
|
||||
PreMergeUnitTestMatrix:
|
||||
needs: [ IdentifyBranches ]
|
||||
if: success()
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(needs.IdentifyBranches.outputs.all_branches) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Unit Tests for branch ${{matrix.branch}}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
is_cherry_pick: true
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
unittest_command: ${{vars.UNITTEST_COMMAND}}
|
||||
|
||||
PreMergeUnitTests:
|
||||
needs: [ IdentifyBranches, PreMergeUnitTestMatrix ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check unit test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.PreMergeUnitTestMatrix.result}}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_PASSED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::All tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::notice::Unit tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.PRE_MERGE_TESTING_IN_PROGRESS}} \
|
||||
--add-label ${{vars.PRE_MERGE_CHECKS_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
echo "::error::One or more tests failed ($RESULT)"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
MergeAndCherryPick:
|
||||
needs: [ IdentifyBranches, PreMergeUnitTests ]
|
||||
if: success()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Start Merge
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--add-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
|
||||
- name: Get Token needed to push cherry-picks
|
||||
id: get_workflow_token
|
||||
uses: peter-murray/workflow-application-token-action@v2
|
||||
with:
|
||||
application_id: ${{secrets.ASTERISK_ORG_ACCESS_APP_ID}}
|
||||
application_private_key: ${{secrets.ASTERISK_ORG_ACCESS_APP_PRIV_KEY}}
|
||||
organization: asterisk
|
||||
|
||||
- name: Merge and Cherry Pick to ${{needs.IdentifyBranches.outputs.branches}}
|
||||
id: mergecp
|
||||
uses: asterisk/asterisk-ci-actions/MergeAndCherryPickComposite@main
|
||||
with:
|
||||
repo: ${{github.repository}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
branches: ${{needs.IdentifyBranches.outputs.branches}}
|
||||
force: ${{env.FORCE}}
|
||||
github_token: ${{steps.get_workflow_token.outputs.token}}
|
||||
|
||||
- name: Merge Cleanup
|
||||
if: always()
|
||||
env:
|
||||
RESULT: ${{ steps.mergecp.outcome }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BRANCH_COUNT: ${{ needs.IdentifyBranches.outputs.branch_count }}
|
||||
BRANCHES: ${{ needs.IdentifyBranches.outputs.branches }}
|
||||
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
if [ $BRANCH_COUNT -eq 0 ] ; then
|
||||
gh pr comment --repo ${{github.repository}} \
|
||||
-b "Successfully merged to branch $BASE_BRANCH." \
|
||||
${{env.PR_NUMBER}} || :
|
||||
else
|
||||
gh pr comment --repo ${{github.repository}} \
|
||||
-b "Successfully merged to branch $BASE_BRANCH and cherry-picked to $BRANCHES" \
|
||||
${{env.PR_NUMBER}} || :
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
failure)
|
||||
gh pr edit --repo ${{github.repository}} \
|
||||
--remove-label ${{vars.MERGE_IN_PROGRESS_LABEL}} \
|
||||
--add-label ${{vars.MERGE_FAILED_LABEL}} \
|
||||
${{env.PR_NUMBER}} || :
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
esac
|
|
@ -0,0 +1,28 @@
|
|||
name: Nightly Admin
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
PR_NUMBER: 0
|
||||
PR_COMMIT: ''
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }} ${{ vars.UNITTEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
CloseStaleIssues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v7
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 7 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
|
||||
stale-issue-label: stale
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 14 days with no activity.'
|
||||
days-before-stale: 7
|
||||
days-before-close: 14
|
||||
days-before-pr-close: -1
|
||||
only-labels: triage,feedback-required
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
name: NightlyTests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{ github.repository }}
|
||||
PR_NUMBER: 0
|
||||
PR_COMMIT: ''
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MODULES_BLACKLIST: ${{ vars.GATETEST_MODULES_BLACKLIST }}
|
||||
|
||||
jobs:
|
||||
AsteriskNightly:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ${{ fromJSON(vars.NIGHTLYTEST_BRANCHES) }}
|
||||
group: ${{ fromJSON(vars.NIGHTLYTEST_LIST) }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Nightly Tests for ${{ matrix.group }}/${{ matrix.branch }}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Nightly
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{matrix.branch}}
|
||||
modules_blacklist: ${{env.MODULES_BLACKLIST}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
testsuite_repo: ${{vars.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{ toJSON(fromJSON(vars.GATETEST_COMMANDS)[matrix.group]) }}
|
||||
|
||||
AsteriskNightlyTests:
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: AsteriskNightly
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT: ${{needs.AsteriskNightly.result}}
|
||||
run: |
|
||||
case $RESULT in
|
||||
success)
|
||||
echo "::notice::All Testsuite tests passed"
|
||||
exit 0
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Testsuite tests were skipped because of an earlier failure"
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more Testsuite tests failed"
|
||||
exit 1
|
||||
esac
|
|
@ -0,0 +1,32 @@
|
|||
name: PRMerged
|
||||
run-name: "PR ${{github.event.number || inputs.pr_number}} ${{github.event.action || 'MANUAL POST MERGE'}} by ${{ github.actor }}"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'PR number'
|
||||
required: true
|
||||
type: number
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number || inputs.pr_number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REPO: ${{github.repository}}
|
||||
PR_NUMBER: ${{github.event.number || inputs.pr_number}}
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
jobs:
|
||||
CloseIssues:
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: wow-actions/auto-close-fixed-issues@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
name: PRSubmitActions
|
||||
run-name: "PRSubmitActions: Test ${{github.event.action}}"
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [PRSubmitTests]
|
||||
types:
|
||||
- requested
|
||||
- completed
|
||||
env:
|
||||
ACTION: ${{ github.event.action }}
|
||||
CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
||||
REPO: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
PRSubmitActions:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get PR Number
|
||||
id: getpr
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let search = `repo:${context.repo.owner}/${context.repo.repo} ${context.payload.workflow_run.head_sha}`;
|
||||
let prs = await github.rest.search.issuesAndPullRequests({
|
||||
q: search,
|
||||
});
|
||||
if (prs.data.total_count == 0) {
|
||||
core.setFailed(`Unable to get PR for ${context.payload.workflow_run.head_sha}`);
|
||||
return;
|
||||
}
|
||||
let pr_number = prs.data.items[0].number;
|
||||
core.setOutput('pr_number', pr_number);
|
||||
return;
|
||||
|
||||
- name: Set Label
|
||||
id: setlabel
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.getpr.outputs.PR_NUMBER }}
|
||||
LABEL_TIP: ${{ vars.PR_SUBMIT_TESTING_IN_PROGRESS }}
|
||||
LABEL_PASS: ${{ vars.PR_SUBMIT_TESTS_PASSED }}
|
||||
LABEL_FAIL: ${{ vars.PR_SUBMIT_TESTS_FAILED }}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let label;
|
||||
if (process.env.ACTION === 'requested') {
|
||||
label = process.env.LABEL_TIP;
|
||||
} else {
|
||||
if ( process.env.CONCLUSION === 'success' ) {
|
||||
label = process.env.LABEL_PASS;
|
||||
} else {
|
||||
label = process.env.LABEL_FAIL;
|
||||
}
|
||||
}
|
||||
core.info(`Setting label ${label}`);
|
||||
github.rest.issues.setLabels({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: [ label ]
|
||||
});
|
||||
return;
|
||||
|
||||
- name: Get cherry-pick branches
|
||||
if: github.event.action == 'completed'
|
||||
id: getbranches
|
||||
uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main
|
||||
with:
|
||||
repo: ${{env.REPO}}
|
||||
pr_number: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: Add cherry-pick reminder
|
||||
if: github.event.action == 'completed'
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
CHERRY_PICK_REMINDER: ${{vars.CHERRY_PICK_REMINDER}}
|
||||
BRANCHES_OUTPUT: ${{toJSON(steps.getbranches.outputs)}}
|
||||
BRANCH_COUNT: ${{steps.getbranches.outputs.branch_count}}
|
||||
FORCED_NONE: ${{steps.getbranches.outputs.forced_none}}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
if (process.env.FORCED_NONE === 'true' ||
|
||||
process.env.BRANCH_COUNT > 0) {
|
||||
core.info("No cherry-pick reminder needed.");
|
||||
return;
|
||||
}
|
||||
let comments = await github.rest.issues.listComments({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
let found = false;
|
||||
for (const c of comments.data) {
|
||||
if (c.body.startsWith("<!--CPR-->")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
core.info("Cherry-pick reminder already exists.");
|
||||
return;
|
||||
}
|
||||
core.info("Adding cherry-pick reminder.");
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: process.env.CHERRY_PICK_REMINDER
|
||||
})
|
||||
return;
|
||||
|
||||
- name: Add reviewers
|
||||
if: github.event.action == 'completed'
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}}
|
||||
REVIEWERS: ${{vars.PR_REVIEWERS}}
|
||||
with:
|
||||
retries: 5
|
||||
script: |
|
||||
let rs = JSON.parse(process.env.REVIEWERS);
|
||||
let users = [];
|
||||
let teams = [];
|
||||
for (const r of rs) {
|
||||
if (r.indexOf("/") > 0) {
|
||||
teams.push(r.split('/')[1]);
|
||||
} else {
|
||||
users.push(r);
|
||||
}
|
||||
}
|
||||
if (teams.length > 0 || users.length > 0) {
|
||||
core.info(`Adding user reviewers ${users}`);
|
||||
core.info(`Adding team reviewers ${teams}`);
|
||||
await github.rest.pulls.requestReviewers({
|
||||
pull_number: process.env.PR_NUMBER,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
reviewers: users,
|
||||
team_reviewers: teams
|
||||
});
|
||||
}
|
||||
return;
|
|
@ -0,0 +1,114 @@
|
|||
name: PRSubmitTests
|
||||
run-name: "PR ${{github.event.number}} ${{github.event.action}} by ${{ github.actor }}"
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: ${{github.workflow}}-${{github.event.number}}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
ASTERISK_REPO: ${{github.repository}}
|
||||
PR_NUMBER: ${{github.event.number}}
|
||||
PR_COMMIT: ${{github.event.pull_request.head.sha}}
|
||||
BRANCH: ${{github.event.pull_request.base.ref}}
|
||||
|
||||
jobs:
|
||||
#
|
||||
# Pull requests created from forked respositories don't have access to
|
||||
# the "Action Variables" ('vars' context) so we need to retrieve control
|
||||
# data from an action.
|
||||
#
|
||||
PRSGetControlData:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
control_data: ${{ steps.setvars.outputs.control_data }}
|
||||
steps:
|
||||
- id: setvars
|
||||
uses: asterisk/asterisk-ci-actions/GetRepoControlData@main
|
||||
with:
|
||||
repo: ${{ github.event.repository.name}}
|
||||
- name: DumpEnvironment
|
||||
uses: asterisk/asterisk-ci-actions/DumpEnvironmentAction@main
|
||||
with:
|
||||
action-inputs: ${{toJSON(inputs)}}
|
||||
action-vars: ${{ toJSON(steps.setvars.outputs) }}
|
||||
|
||||
PRSUnitTests:
|
||||
needs: PRSGetControlData
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
UNITTEST_COMMAND: ${{ fromJSON(needs.PRSGetControlData.outputs.control_data).UNITTEST_COMMAND }}
|
||||
steps:
|
||||
- name: Run Unit Tests
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main
|
||||
with:
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{env.BRANCH}}
|
||||
unittest_command: ${{env.UNITTEST_COMMAND}}
|
||||
|
||||
PRSGateTestMatrix:
|
||||
runs-on: ubuntu-latest
|
||||
needs: PRSGetControlData
|
||||
continue-on-error: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
group: ${{ fromJSON(fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_LIST) }}
|
||||
env:
|
||||
TESTSUITE_REPO: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).TESTSUITE_REPO }}"
|
||||
GATETEST_COMMANDS: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_COMMANDS }}"
|
||||
GATETEST_COMMAND: "${{ toJSON(fromJSON(fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_COMMANDS)[matrix.group]) }}"
|
||||
steps:
|
||||
- id: runtest
|
||||
name: Run Gate Tests for ${{ matrix.group }}
|
||||
uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main
|
||||
with:
|
||||
test_type: Gate
|
||||
asterisk_repo: ${{env.ASTERISK_REPO}}
|
||||
pr_number: ${{env.PR_NUMBER}}
|
||||
base_branch: ${{env.BRANCH}}
|
||||
testsuite_repo: ${{env.TESTSUITE_REPO}}
|
||||
gatetest_group: ${{matrix.group}}
|
||||
gatetest_command: ${{env.GATETEST_COMMAND}}
|
||||
|
||||
PRSTestResults:
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
needs: [PRSUnitTests,PRSGateTestMatrix]
|
||||
steps:
|
||||
- name: Check test matrix status
|
||||
env:
|
||||
RESULT_UNIT: ${{ needs.PRSUnitTests.result }}
|
||||
RESULT_GATE: ${{ needs.PRSGateTestMatrix.result }}
|
||||
run: |
|
||||
declare -i rc=0
|
||||
echo "all results: ${{ toJSON(needs.*.result) }}"
|
||||
case $RESULT_UNIT in
|
||||
success)
|
||||
echo "::notice::Unit tests passed"
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Unit tests were skipped because of an earlier failure"
|
||||
rc+=1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more unit tests failed ($RESULT_UNIT)"
|
||||
rc+=1
|
||||
esac
|
||||
case $RESULT_GATE in
|
||||
success)
|
||||
echo "::notice::Gate tests passed"
|
||||
;;
|
||||
skipped)
|
||||
echo "::error::Gate tests were skipped because of an earlier failure"
|
||||
rc+=1
|
||||
;;
|
||||
*)
|
||||
echo "::error::One or more gate tests failed ($RESULT_GATE)"
|
||||
rc+=1
|
||||
esac
|
||||
echo "::notice::Final result code: $rc"
|
||||
exit $rc
|
|
@ -0,0 +1,99 @@
|
|||
name: Releaser
|
||||
run-name: ${{ github.actor }} is creating ${{vars.PRODUCT_NAME}} release ${{inputs.new_version}}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
new_version:
|
||||
description: |
|
||||
New Version:
|
||||
Examples:
|
||||
20.4.0-rc1, 20.4.0-rc2, 20.4.0, 20.4.1
|
||||
certified-20.4-cert1-rc1, certified-20.4-cert1
|
||||
required: true
|
||||
type: string
|
||||
is_security:
|
||||
description: |
|
||||
Security?
|
||||
(No prev RCs)
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
advisories:
|
||||
description: |
|
||||
Comma separated list of advisories.
|
||||
NO SPACES
|
||||
Example: GHSA-4xjp-22g4-9fxm,GHSA-4xjp-22g4-zzzz
|
||||
required: false
|
||||
type: string
|
||||
is_hotfix:
|
||||
description: |
|
||||
Hotfix?
|
||||
(A patch release but not security. No prev RCs)
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
force_cherry_pick:
|
||||
description: |
|
||||
Force cherry-pick for non-RC1 releases? USE WITH CAUTION!
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
push_release_branches:
|
||||
description: |
|
||||
Push release branches live?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
create_github_release:
|
||||
description: |
|
||||
Create the GitHub release?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
push_tarballs:
|
||||
description: |
|
||||
Push tarballs to downloads server?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
send_email:
|
||||
description: |
|
||||
Send announcement emails?
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
ReleaseAsterisk:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run Releaser
|
||||
uses: asterisk/asterisk-ci-actions/ReleaserComposite@main
|
||||
with:
|
||||
product: ${{vars.PRODUCT_NAME}}
|
||||
is_security: ${{inputs.is_security}}
|
||||
advisories: ${{inputs.advisories}}
|
||||
is_hotfix: ${{inputs.is_hotfix}}
|
||||
new_version: ${{inputs.new_version}}
|
||||
force_cherry_pick: ${{inputs.force_cherry_pick}}
|
||||
push_release_branches: ${{inputs.push_release_branches}}
|
||||
create_github_release: ${{inputs.create_github_release}}
|
||||
push_tarballs: ${{inputs.push_tarballs}}
|
||||
send_email: ${{inputs.send_email}}
|
||||
repo: ${{github.repository}}
|
||||
mail_list_ga: ${{vars.MAIL_LIST_GA}}
|
||||
mail_list_rc: ${{vars.MAIL_LIST_RC}}
|
||||
mail_list_cert_ga: ${{vars.MAIL_LIST_CERT_GA}}
|
||||
mail_list_cert_rc: ${{vars.MAIL_LIST_CERT_RC}}
|
||||
mail_list_sec: ${{vars.MAIL_LIST_SEC_ADV}}
|
||||
sec_adv_url_base: ${{vars.SEC_ADV_URL_BASE}}
|
||||
gpg_private_key: ${{secrets.ASTDEV_GPG_PRIV_KEY}}
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
application_id: ${{secrets.ASTERISK_ORG_ACCESS_APP_ID}}
|
||||
application_private_key: ${{secrets.ASTERISK_ORG_ACCESS_APP_PRIV_KEY}}
|
||||
asteriskteamsa_username: ${{secrets.ASTERISKTEAMSA_GMAIL_ACCT}}
|
||||
asteriskteamsa_token: ${{secrets.ASTERISKTEAMSA_GMAIL_TOKEN}}
|
||||
deploy_ssh_priv_key: ${{secrets.DOWNLOADS_DEPLOY_SSH_PRIV_KEY}}
|
||||
deploy_ssh_username: ${{secrets.DOWNLOADS_DEPLOY_SSH_USERNAME}}
|
||||
deploy_host: ${{vars.DEPLOY_HOST}}
|
||||
deploy_dir: ${{vars.DEPLOY_DIR}}
|
11
.gitreview
11
.gitreview
|
@ -1,11 +0,0 @@
|
|||
[gerrit]
|
||||
defaultbranch=master
|
||||
basebranch=master
|
||||
#
|
||||
# Intentional padding to ensure it is possible to point a commit
|
||||
# to an alternative gerrit server/repository without breaking
|
||||
# cherry-pick between branches.
|
||||
#
|
||||
host=gerrit.asterisk.org
|
||||
port=29418
|
||||
project=asterisk.git
|
|
@ -0,0 +1 @@
|
|||
40
|
10
BUGS
10
BUGS
|
@ -1,22 +1,22 @@
|
|||
Asterisk Bug Tracking Information
|
||||
=================================
|
||||
|
||||
To learn about and report Asterisk bugs, please visit
|
||||
To learn about and report Asterisk bugs, please visit
|
||||
the official Asterisk Bug Tracker at:
|
||||
|
||||
https://issues.asterisk.org/jira
|
||||
https://github.com/asterisk/asterisk/issues/
|
||||
|
||||
For more information on using the bug tracker, or to
|
||||
For more information on using the bug tracker, or to
|
||||
learn how you can contribute by acting as a bug marshal
|
||||
please see:
|
||||
|
||||
http://www.asterisk.org/developers/bug-guidelines
|
||||
https://docs.asterisk.org/Asterisk-Community/Asterisk-Issue-Guidelines/
|
||||
|
||||
If you would like to submit a feature request, please
|
||||
resist the temptation to post it to the bug tracker.
|
||||
Feature requests should be posted to the asterisk-dev
|
||||
mailing list, located at:
|
||||
|
||||
http://lists.digium.com
|
||||
http://lists.digium.com
|
||||
|
||||
Thank you!
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ChangeLogs/ChangeLog-20.7.0.md
|
|
@ -0,0 +1,741 @@
|
|||
|
||||
Change Log for Release 20.3.0
|
||||
========================================
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- Set up new ChangeLogs directory
|
||||
- .github: Add AsteriskReleaser
|
||||
- chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
- cel: add local optimization begin event
|
||||
- core: Cleanup gerrit and JIRA references. (#57)
|
||||
- .github: Fix CherryPickTest to only run when it should
|
||||
- .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
- .github: Remove separate set labels step from new PR
|
||||
- .github: Refactor CP progress and add new PR test progress
|
||||
- res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
- .github: Add cherry-pick test progress labels
|
||||
- LICENSE: Update link to trademark policy.
|
||||
- chan_dahdi: Add dialmode option for FXS lines.
|
||||
- .github: Update issue templates
|
||||
- .github: Remove unnecessary parameter in CherryPickTest
|
||||
- Initial GitHub PRs
|
||||
- Initial GitHub Issue Templates
|
||||
- pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
- Revert "app_queue: periodic announcement configurable start time."
|
||||
- res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
- pbx_dundi: Add PJSIP support.
|
||||
- install_prereq: Add Linux Mint support.
|
||||
- chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
- voicemail.conf: Fix incorrect comment about #include.
|
||||
- app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
- test.c: Fix counting of tests and add 2 new tests
|
||||
- res_calendar: output busy state as part of show calendar.
|
||||
- loader.c: Minor module key check simplification.
|
||||
- ael: Regenerate lexers and parsers.
|
||||
- bridge_builtin_features: add beep via touch variable
|
||||
- res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
- format_sln: add .slin as supported file extension
|
||||
- res_agi: RECORD FILE plays 2 beeps.
|
||||
- func_json: Fix JSON parsing issues.
|
||||
- app_senddtmf: Add SendFlash AMI action.
|
||||
- app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
- configure: fix detection of re-entrant resolver functions
|
||||
- cli: increase channel column width
|
||||
- app_queue: periodic announcement configurable start time.
|
||||
- make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
- res_http_media_cache: Introduce options and customize
|
||||
- main/iostream.c: fix build with libressl
|
||||
- contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
The new AST_CEL_LOCAL_OPTIMIZE_BEGIN can be used
|
||||
by itself or in conert with the existing
|
||||
AST_CEL_LOCAL_OPTIMIZE to book-end local channel optimizaion.
|
||||
|
||||
- ### chan_dahdi: Add dialmode option for FXS lines.
|
||||
A "dialmode" option has been added which allows
|
||||
specifying, on a per-channel basis, what methods of
|
||||
subscriber dialing (pulse and/or tone) are permitted.
|
||||
Additionally, this can be changed on a channel
|
||||
at any point during a call using the CHANNEL
|
||||
function.
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
DUNDi now supports chan_pjsip. Outgoing calls using
|
||||
PJSIP require the pjsip_outgoing_endpoint option
|
||||
to be set in dundi.conf.
|
||||
|
||||
- ### cli: increase channel column width
|
||||
This change increases the display width on 'core show channels'
|
||||
amd 'core show channels verbose'
|
||||
For 'core show channels', the Channel name field is increased to
|
||||
64 characters and the Location name field is increased to 32
|
||||
characters.
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
The SendFlash AMI action now allows sending
|
||||
a hook flash event on a channel.
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
The res_http_media_cache module now attempts to load
|
||||
configuration from the res_http_media_cache.conf file.
|
||||
The following options were added:
|
||||
* timeout_secs
|
||||
* user_agent
|
||||
* follow_location
|
||||
* max_redirects
|
||||
* protocols
|
||||
* redirect_protocols
|
||||
* dns_cache_timeout_secs
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
Also added two new unit tests that just pass and fail
|
||||
to be used for testing CI itself.
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
It is now possible to specify the MixMonitorID when calling
|
||||
the manager action: MixMonitorMute. This will allow an
|
||||
individual MixMonitor instance to be muted via ID.
|
||||
The MixMonitorID can be stored as a channel variable using
|
||||
the 'i' MixMonitor option and is returned upon creation if
|
||||
this option is used.
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor audiohooks on the channel. Previous
|
||||
behavior would set the flag on the first MixMonitor audiohook
|
||||
found.
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Add optional touch variable : TOUCH_MIXMONITOR_BEEP(interval)
|
||||
Setting TOUCH_MIXMONITOR_BEEP/TOUCH_MONITOR_BEEP to a valid
|
||||
interval in seconds will result in a periodic beep being
|
||||
played to the monitored channel upon MixMontior/Monitor
|
||||
feature start.
|
||||
If an interval less than 5 seconds is specified, the interval
|
||||
will default to 5 seconds. If the value is set to an invalid
|
||||
interval, the default of 15 seconds will be used.
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
format_sln now recognizes '.slin' as a valid
|
||||
file extension in addition to the existing
|
||||
'.sln' and '.raw'.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
The existing AST_CEL_LOCAL_OPTIMIZE can continue
|
||||
to be used as-is and the AST_CEL_LOCAL_OPTIMIZE_BEGIN event
|
||||
can be ignored if desired.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #35: [New Feature]: chan_dahdi: Allow disabling pulse or tone dialing
|
||||
- #39: [Bug]: Remove .gitreview from repository.
|
||||
- #43: [Bug]: Link to trademark policy is no longer correct
|
||||
- #48: [bug]: res_pjsip: Mediasec requires different headers on 401 response
|
||||
- #52: [improvement]: Add local optimization begin cel event
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (1):
|
||||
- Update for 20.3.0-rc1
|
||||
|
||||
- ### Fabrice Fontaine (2):
|
||||
- main/iostream.c: fix build with libressl
|
||||
- configure: fix detection of re-entrant resolver functions
|
||||
|
||||
- ### George Joseph (13):
|
||||
- make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
- test.c: Fix counting of tests and add 2 new tests
|
||||
- Initial GitHub Issue Templates
|
||||
- Initial GitHub PRs
|
||||
- .github: Remove unnecessary parameter in CherryPickTest
|
||||
- .github: Update issue templates
|
||||
- .github: Add cherry-pick test progress labels
|
||||
- .github: Refactor CP progress and add new PR test progress
|
||||
- .github: Remove separate set labels step from new PR
|
||||
- .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
- .github: Fix CherryPickTest to only run when it should
|
||||
- .github: Add AsteriskReleaser
|
||||
- Set up new ChangeLogs directory
|
||||
|
||||
- ### Henning Westerholt (2):
|
||||
- chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
- chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
|
||||
- ### Holger Hans Peter Freyther (1):
|
||||
- res_http_media_cache: Introduce options and customize
|
||||
|
||||
- ### Jaco Kroon (2):
|
||||
- app_queue: periodic announcement configurable start time.
|
||||
- res_calendar: output busy state as part of show calendar.
|
||||
|
||||
- ### Joshua C. Colp (2):
|
||||
- pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
- LICENSE: Update link to trademark policy.
|
||||
|
||||
- ### Joshua Colp (1):
|
||||
- Revert "app_queue: periodic announcement configurable start time."
|
||||
|
||||
- ### Maximilian Fridrich (1):
|
||||
- res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
|
||||
- ### Mike Bradeen (5):
|
||||
- cli: increase channel column width
|
||||
- format_sln: add .slin as supported file extension
|
||||
- res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
- bridge_builtin_features: add beep via touch variable
|
||||
- cel: add local optimization begin event
|
||||
|
||||
- ### Naveen Albert (8):
|
||||
- app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
- app_senddtmf: Add SendFlash AMI action.
|
||||
- func_json: Fix JSON parsing issues.
|
||||
- app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
- voicemail.conf: Fix incorrect comment about #include.
|
||||
- pbx_dundi: Add PJSIP support.
|
||||
- res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
- chan_dahdi: Add dialmode option for FXS lines.
|
||||
|
||||
- ### Sean Bright (5):
|
||||
- contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
- res_agi: RECORD FILE plays 2 beeps.
|
||||
- ael: Regenerate lexers and parsers.
|
||||
- loader.c: Minor module key check simplification.
|
||||
- core: Cleanup gerrit and JIRA references. (#57)
|
||||
|
||||
- ### The_Blode (1):
|
||||
- install_prereq: Add Linux Mint support.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### Set up new ChangeLogs directory
|
||||
Author: George Joseph
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Add AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-05-05
|
||||
|
||||
|
||||
- ### chan_pjsip: also return all codecs on empty re-INVITE for late offers
|
||||
Author: Henning Westerholt
|
||||
Date: 2023-05-03
|
||||
|
||||
We should also return all codecs on an re-INVITE without SDP for a
|
||||
call that used late offer (e.g. no SDP in the initial INVITE, SDP
|
||||
in the ACK). Bugfix for feature introduced in ASTERISK-30193
|
||||
(https://issues.asterisk.org/jira/browse/ASTERISK-30193)
|
||||
|
||||
Migration from previous gerrit change that was not merged.
|
||||
|
||||
|
||||
- ### cel: add local optimization begin event
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-02
|
||||
|
||||
The current AST_CEL_LOCAL_OPTIMIZE event is and has been
|
||||
triggered on a local optimization end to serve as a flag
|
||||
indicating the event occurred. This change adds a second
|
||||
AST_CEL_LOCAL_OPTIMIZE_BEGIN event for further detail.
|
||||
|
||||
Resolves: #52
|
||||
|
||||
UpgradeNote: The existing AST_CEL_LOCAL_OPTIMIZE can continue
|
||||
to be used as-is and the AST_CEL_LOCAL_OPTIMIZE_BEGIN event
|
||||
can be ignored if desired.
|
||||
|
||||
UserNote: The new AST_CEL_LOCAL_OPTIMIZE_BEGIN can be used
|
||||
by itself or in conert with the existing
|
||||
AST_CEL_LOCAL_OPTIMIZE to book-end local channel optimizaion.
|
||||
|
||||
|
||||
- ### core: Cleanup gerrit and JIRA references. (#57)
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-03
|
||||
|
||||
* Remove .gitreview and switch to pulling the main asterisk branch
|
||||
version from configure.ac instead.
|
||||
|
||||
* Replace references to JIRA with GitHub.
|
||||
|
||||
* Other minor cleanup found along the way.
|
||||
|
||||
Resolves: #39
|
||||
|
||||
- ### .github: Fix CherryPickTest to only run when it should
|
||||
Author: George Joseph
|
||||
Date: 2023-05-03
|
||||
|
||||
Fixed CherryPickTest so it triggers only on the
|
||||
"cherry-pick-test" label instead of all labels.
|
||||
|
||||
|
||||
- ### .github: Fix reference to CHERRY_PICK_TESTING_IN_PROGRESS
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### .github: Remove separate set labels step from new PR
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### .github: Refactor CP progress and add new PR test progress
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### res_pjsip: mediasec: Add Security-Client headers after 401
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-02
|
||||
|
||||
When using mediasec, requests sent after a 401 must still contain the
|
||||
Security-Client header according to
|
||||
draft-dawes-sipcore-mediasec-parameter.
|
||||
|
||||
Resolves: #48
|
||||
|
||||
- ### .github: Add cherry-pick test progress labels
|
||||
Author: George Joseph
|
||||
Date: 2023-05-02
|
||||
|
||||
|
||||
- ### LICENSE: Update link to trademark policy.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-01
|
||||
|
||||
Resolves: #43
|
||||
|
||||
- ### chan_dahdi: Add dialmode option for FXS lines.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-04-28
|
||||
|
||||
Currently, both pulse and tone dialing are always enabled
|
||||
on all FXS lines, with no way of disabling one or the other.
|
||||
|
||||
In some circumstances, it is desirable or necessary to
|
||||
disable one of these, and this behavior can be problematic.
|
||||
|
||||
A new "dialmode" option is added which allows setting the
|
||||
methods to support on a per channel basis for FXS (FXO
|
||||
signalled lines). The four options are "both", "pulse",
|
||||
"dtmf"/"tone", and "none".
|
||||
|
||||
Additionally, integration with the CHANNEL function is
|
||||
added so that this setting can be updated for a channel
|
||||
during a call.
|
||||
|
||||
Resolves: #35
|
||||
ASTERISK-29992
|
||||
|
||||
UserNote: A "dialmode" option has been added which allows
|
||||
specifying, on a per-channel basis, what methods of
|
||||
subscriber dialing (pulse and/or tone) are permitted.
|
||||
|
||||
Additionally, this can be changed on a channel
|
||||
at any point during a call using the CHANNEL
|
||||
function.
|
||||
|
||||
|
||||
- ### .github: Update issue templates
|
||||
Author: George Joseph
|
||||
Date: 2023-05-01
|
||||
|
||||
|
||||
- ### .github: Remove unnecessary parameter in CherryPickTest
|
||||
Author: George Joseph
|
||||
Date: 2023-05-01
|
||||
|
||||
|
||||
- ### Initial GitHub PRs
|
||||
Author: George Joseph
|
||||
Date: 2023-04-28
|
||||
|
||||
|
||||
- ### Initial GitHub Issue Templates
|
||||
Author: George Joseph
|
||||
Date: 2023-04-28
|
||||
|
||||
|
||||
- ### pbx_dundi: Fix PJSIP endpoint configuration check.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-04-13
|
||||
|
||||
ASTERISK-28233
|
||||
|
||||
|
||||
- ### Revert "app_queue: periodic announcement configurable start time."
|
||||
Author: Joshua Colp
|
||||
Date: 2023-04-11
|
||||
|
||||
This reverts commit 3fd0b65bae4b1b14434737ffcf0da4aa9ff717f6.
|
||||
|
||||
Reason for revert: Causes segmentation fault.
|
||||
|
||||
|
||||
- ### res_pjsip_stir_shaken: Fix JSON field ordering and disallowed TN characters.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-17
|
||||
|
||||
The current STIR/SHAKEN signing process is inconsistent with the
|
||||
RFCs in a couple ways that can cause interoperability issues.
|
||||
|
||||
RFC8225 specifies that the keys must be ordered lexicographically, but
|
||||
currently the fields are simply ordered according to the order
|
||||
in which they were added to the JSON object, which is not
|
||||
compliant with the RFC and can cause issues with some carriers.
|
||||
|
||||
To fix this, we now leverage libjansson's ability to dump a JSON
|
||||
object sorted by key value, yielding the correct field ordering.
|
||||
|
||||
Additionally, telephone numbers must have any leading + prefix removed
|
||||
and must not contain characters outside of 0-9, *, and # in order
|
||||
to comply with the RFCs. Numbers are now properly formatted as such.
|
||||
|
||||
ASTERISK-30407 #close
|
||||
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
Author: Naveen Albert
|
||||
Date: 2022-12-09
|
||||
|
||||
Adds PJSIP as a supported technology to DUNDi.
|
||||
|
||||
To facilitate this, we now allow an endpoint to be specified
|
||||
for outgoing PJSIP calls. We also allow users to force a specific
|
||||
channel technology for outgoing SIP-protocol calls.
|
||||
|
||||
ASTERISK-28109 #close
|
||||
ASTERISK-28233 #close
|
||||
|
||||
|
||||
- ### install_prereq: Add Linux Mint support.
|
||||
Author: The_Blode
|
||||
Date: 2023-03-17
|
||||
|
||||
ASTERISK-30359 #close
|
||||
|
||||
|
||||
- ### chan_pjsip: fix music on hold continues after INVITE with replaces
|
||||
Author: Henning Westerholt
|
||||
Date: 2023-03-21
|
||||
|
||||
In a three party scenario with INVITE with replaces, we need to
|
||||
unhold the call, otherwise one party continues to get music on
|
||||
hold, and the call is not properly bridged between them.
|
||||
|
||||
ASTERISK-30428
|
||||
|
||||
|
||||
- ### voicemail.conf: Fix incorrect comment about #include.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-03-28
|
||||
|
||||
A comment at the top of voicemail.conf says that #include
|
||||
cannot be used in voicemail.conf because this breaks
|
||||
the ability for app_voicemail to auto-update passwords.
|
||||
This is factually incorrect, since Asterisk has no problem
|
||||
updating files that are #include'd in the main configuration
|
||||
file, and this does work in voicemail.conf as well.
|
||||
|
||||
ASTERISK-30479 #close
|
||||
|
||||
|
||||
- ### app_queue: Fix minor xmldoc duplication and vagueness.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-04-03
|
||||
|
||||
The F option in the xmldocs for the Queue application
|
||||
was erroneously duplicated, causing it to display
|
||||
twice on the wiki. The two sections are now merged into one.
|
||||
|
||||
Additionally, the description for the d option was quite
|
||||
vague. Some more details are added to provide context
|
||||
as to what this actually does.
|
||||
|
||||
ASTERISK-30486 #close
|
||||
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
Author: George Joseph
|
||||
Date: 2023-03-28
|
||||
|
||||
The unit test XML output was counting all registered tests as "run"
|
||||
even when only a subset were actually requested to be run and
|
||||
the "failures" attribute was missing.
|
||||
|
||||
* The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
|
||||
* The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
|
||||
Also added 2 new unit tests that just pass and fail to be
|
||||
used for CI testing.
|
||||
|
||||
|
||||
- ### res_calendar: output busy state as part of show calendar.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-03-23
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### loader.c: Minor module key check simplification.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-23
|
||||
|
||||
|
||||
- ### ael: Regenerate lexers and parsers.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-21
|
||||
|
||||
Various changes to ensure that the lexers and parsers can be correctly
|
||||
generated when REBUILD_PARSERS is enabled.
|
||||
|
||||
Some notes:
|
||||
|
||||
* Because of the version of flex we are using to generate the lexers
|
||||
(2.5.35) some post-processing in the Makefile is still required.
|
||||
|
||||
* The generated lexers do not contain the problematic C99 check that
|
||||
was being replaced by the call to sed in the respective Makefiles so
|
||||
it was removed.
|
||||
|
||||
* Since these files are generated, they will include trailing
|
||||
whitespace in some places. This does not need to be corrected.
|
||||
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-01
|
||||
|
||||
Add periodic beep option to one-touch recording by setting
|
||||
the touch variable TOUCH_MONITOR_BEEP or
|
||||
TOUCH_MIXMONITOR_BEEP to the desired interval in seconds.
|
||||
|
||||
If the interval is less than 5 seconds, a minimum of 5
|
||||
seconds will be imposed. If the interval is set to an
|
||||
invalid value, it will default to 15 seconds.
|
||||
|
||||
A new test event PERIODIC_HOOK_ENABLED was added to the
|
||||
func_periodic_hook hook_on function to indicate when
|
||||
a hook is started. This is so we can test that the touch
|
||||
variable starts the hook as expected.
|
||||
|
||||
ASTERISK-30446
|
||||
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-13
|
||||
|
||||
While it is possible to create multiple mixmonitor instances
|
||||
on a channel, it was not previously possible to mute individual
|
||||
instances.
|
||||
|
||||
This change includes the ability to specify the MixMonitorID
|
||||
when calling the manager action: MixMonitorMute. This will
|
||||
allow an individual MixMonitor instance to be muted via id.
|
||||
This id can be stored as a channel variable using the 'i'
|
||||
MixMonitor option.
|
||||
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor spy-type audiohooks on the channel.
|
||||
This is done via the new audiohook function:
|
||||
ast_audiohook_set_mute_all.
|
||||
|
||||
ASTERISK-30464
|
||||
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-14
|
||||
|
||||
Adds '.slin' to existing supported file extensions:
|
||||
.sln and .raw
|
||||
|
||||
ASTERISK-30465
|
||||
|
||||
|
||||
- ### res_agi: RECORD FILE plays 2 beeps.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-08
|
||||
|
||||
Sending the "RECORD FILE" command without the optional
|
||||
`offset_samples` argument can result in two beeps playing on the
|
||||
channel.
|
||||
|
||||
This bug has been present since Asterisk 0.3.0 (2003-02-06).
|
||||
|
||||
ASTERISK-30457 #close
|
||||
|
||||
|
||||
- ### func_json: Fix JSON parsing issues.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-26
|
||||
|
||||
Fix issue with returning empty instead of dumping
|
||||
the JSON string when recursing.
|
||||
|
||||
Also adds a unit test to capture this fix.
|
||||
|
||||
ASTERISK-30441 #close
|
||||
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-02-26
|
||||
|
||||
Adds an AMI action to send a flash event
|
||||
on a channel.
|
||||
|
||||
ASTERISK-30440 #close
|
||||
|
||||
|
||||
- ### app_dial: Fix DTMF not relayed to caller on unanswered calls.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-03-04
|
||||
|
||||
DTMF frames are not handled in app_dial when sent towards the
|
||||
caller. This means that if DTMF is sent to the calling party
|
||||
and the call has not yet been answered, the DTMF is not audible.
|
||||
This is now fixed by relaying DTMF frames if only a single
|
||||
destination is being dialed.
|
||||
|
||||
ASTERISK-29516 #close
|
||||
|
||||
|
||||
- ### configure: fix detection of re-entrant resolver functions
|
||||
Author: Fabrice Fontaine
|
||||
Date: 2023-03-08
|
||||
|
||||
uClibc does not provide res_nsearch:
|
||||
asterisk-16.0.0/main/dns.c:506: undefined reference to `res_nsearch'
|
||||
|
||||
Patch coded by Yann E. MORIN:
|
||||
http://lists.busybox.net/pipermail/buildroot/2018-October/232630.html
|
||||
|
||||
ASTERISK-21795 #close
|
||||
|
||||
Signed-off-by: Bernd Kuhls <bernd.kuhls@t-online.de>
|
||||
[Retrieved from:
|
||||
https: //git.buildroot.net/buildroot/tree/package/asterisk/0005-configure-fix-detection-of-re-entrant-resolver-funct.patch]
|
||||
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
|
||||
|
||||
- ### cli: increase channel column width
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-03-06
|
||||
|
||||
For 'core show channels', the Channel name field is increased
|
||||
to 64 characters and the Location name field is increased to
|
||||
32 characters.
|
||||
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
ASTERISK-30455
|
||||
|
||||
|
||||
- ### app_queue: periodic announcement configurable start time.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-02-21
|
||||
|
||||
This newly introduced periodic-announce-startdelay makes it possible to
|
||||
configure the initial start delay of the first periodic announcement
|
||||
after which periodic-announce-frequency takes over.
|
||||
|
||||
ASTERISK-30437 #close
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### make_version: Strip svn stuff and suppress ref HEAD errors
|
||||
Author: George Joseph
|
||||
Date: 2023-03-13
|
||||
|
||||
* All of the code that used subversion has been removed.
|
||||
|
||||
* When Asterisk is checked out from a tag or commit instead
|
||||
of one of the regular branches, git would emit messages like
|
||||
"fatal: ref HEAD is not a symbolic ref" which weren't fatal
|
||||
at all. Those are now suppressed.
|
||||
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
Author: Holger Hans Peter Freyther
|
||||
Date: 2022-10-16
|
||||
|
||||
Make the existing CURL parameters configurable and allow
|
||||
to specify the usable protocols, proxy and DNS timeout.
|
||||
|
||||
ASTERISK-30340
|
||||
|
||||
|
||||
- ### main/iostream.c: fix build with libressl
|
||||
Author: Fabrice Fontaine
|
||||
Date: 2023-02-25
|
||||
|
||||
Fix the following build failure with libressl by using SSL_is_server
|
||||
which is available since version 2.7.0 and
|
||||
https://github.com/libressl-portable/openbsd/commit/d7ec516916c5eaac29b02d7a8ac6570f63b458f7:
|
||||
|
||||
iostream.c: In function 'ast_iostream_close':
|
||||
iostream.c:559:41: error: invalid use of incomplete typedef 'SSL' {aka 'struct ssl_st'}
|
||||
559 | if (!stream->ssl->server) {
|
||||
| ^~
|
||||
|
||||
ASTERISK-30107 #close
|
||||
|
||||
Fixes: - http://autobuild.buildroot.org/results/ce4d62d00bb77ba5b303cacf6be7e350581a62f9
|
||||
|
||||
- ### contrib: rc.archlinux.asterisk uses invalid redirect.
|
||||
Author: Sean Bright
|
||||
Date: 2023-03-02
|
||||
|
||||
`rc.archlinux.asterisk`, which explicitly requests bash in its
|
||||
shebang, uses the following command syntax:
|
||||
|
||||
${DAEMON} -rx "core stop now" > /dev/null 2&>1
|
||||
|
||||
The intent of which is to execute:
|
||||
|
||||
${DAEMON} -rx "core stop now"
|
||||
|
||||
While sending both stdout and stderr to `/dev/null`. Unfortunately,
|
||||
because the `&` is in the wrong place, bash is interpreting the `2` as
|
||||
just an additional argument to the `$DAEMON` command and not as a file
|
||||
descriptor and proceeds to use the bashism `&>` to send stderr and
|
||||
stdout to a file named `1`.
|
||||
|
||||
So we clean it up and just use bash's shortcut syntax.
|
||||
|
||||
Issue raised and a fix suggested (but not used) by peutch on GitHub¹.
|
||||
|
||||
ASTERISK-30449 #close
|
||||
|
||||
1. https://github.com/asterisk/asterisk/pull/31
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
Change Log for Release 20.3.1
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.3.1.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.3.0...20.3.1)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.3.1.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- apply_patches: Use globbing instead of file/sort.
|
||||
- apply_patches: Sort patch list before applying
|
||||
- pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_http_media_cache: Introduce options and customize
|
||||
The res_http_media_cache module now attempts to load
|
||||
configuration from the res_http_media_cache.conf file.
|
||||
The following options were added:
|
||||
* timeout_secs
|
||||
* user_agent
|
||||
* follow_location
|
||||
* max_redirects
|
||||
* protocols
|
||||
* redirect_protocols
|
||||
* dns_cache_timeout_secs
|
||||
|
||||
- ### format_sln: add .slin as supported file extension
|
||||
format_sln now recognizes '.slin' as a valid
|
||||
file extension in addition to the existing
|
||||
'.sln' and '.raw'.
|
||||
|
||||
- ### bridge_builtin_features: add beep via touch variable
|
||||
Add optional touch variable : TOUCH_MIXMONITOR_BEEP(interval)
|
||||
Setting TOUCH_MIXMONITOR_BEEP/TOUCH_MONITOR_BEEP to a valid
|
||||
interval in seconds will result in a periodic beep being
|
||||
played to the monitored channel upon MixMontior/Monitor
|
||||
feature start.
|
||||
If an interval less than 5 seconds is specified, the interval
|
||||
will default to 5 seconds. If the value is set to an invalid
|
||||
interval, the default of 15 seconds will be used.
|
||||
|
||||
- ### app_senddtmf: Add SendFlash AMI action.
|
||||
The SendFlash AMI action now allows sending
|
||||
a hook flash event on a channel.
|
||||
|
||||
- ### res_mixmonitor: MixMonitorMute by MixMonitor ID
|
||||
It is now possible to specify the MixMonitorID when calling
|
||||
the manager action: MixMonitorMute. This will allow an
|
||||
individual MixMonitor instance to be muted via ID.
|
||||
The MixMonitorID can be stored as a channel variable using
|
||||
the 'i' MixMonitor option and is returned upon creation if
|
||||
this option is used.
|
||||
As part of this change, if no MixMonitorID is specified in
|
||||
the manager action MixMonitorMute, Asterisk will set the mute
|
||||
flag on all MixMonitor audiohooks on the channel. Previous
|
||||
behavior would set the flag on the first MixMonitor audiohook
|
||||
found.
|
||||
|
||||
- ### pbx_dundi: Add PJSIP support.
|
||||
DUNDi now supports chan_pjsip. Outgoing calls using
|
||||
PJSIP require the pjsip_outgoing_endpoint option
|
||||
to be set in dundi.conf.
|
||||
|
||||
- ### test.c: Fix counting of tests and add 2 new tests
|
||||
The "tests" attribute of the "testsuite" element in the
|
||||
output XML now reflects only the tests actually requested
|
||||
to be executed instead of all the tests registered.
|
||||
The "failures" attribute was added to the "testsuite"
|
||||
element.
|
||||
Also added two new unit tests that just pass and fail
|
||||
to be used for testing CI itself.
|
||||
|
||||
- ### cli: increase channel column width
|
||||
This change increases the display width on 'core show channels'
|
||||
amd 'core show channels verbose'
|
||||
For 'core show channels', the Channel name field is increased to
|
||||
64 characters and the Location name field is increased to 32
|
||||
characters.
|
||||
For 'core show channels verbose', the Channel name field is
|
||||
increased to 80 characters, the Context is increased to 24
|
||||
characters and the Extension is increased to 24 characters.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #193: [bug]: third-party/apply-patches doesn't sort the patch file list before applying
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### George Joseph (1):
|
||||
- apply_patches: Sort patch list before applying
|
||||
|
||||
- ### Sean Bright (1):
|
||||
- apply_patches: Use globbing instead of file/sort.
|
||||
|
||||
- ### Stanislav Abramenkov (1):
|
||||
- pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### apply_patches: Use globbing instead of file/sort.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-06
|
||||
|
||||
This accomplishes the same thing as a `find ... | sort` but with the
|
||||
added benefit of clarity and avoiding a call to a subshell.
|
||||
|
||||
Additionally drop the -s option from call to patch as it is not POSIX.
|
||||
|
||||
- ### apply_patches: Sort patch list before applying
|
||||
Author: George Joseph
|
||||
Date: 2023-07-06
|
||||
|
||||
The apply_patches script wasn't sorting the list of patches in
|
||||
the "patches" directory before applying them. This left the list
|
||||
in an indeterminate order. In most cases, the list is actually
|
||||
sorted but rarely, they can be out of order and cause dependent
|
||||
patches to fail to apply.
|
||||
|
||||
We now sort the list but the "sort" program wasn't in the
|
||||
configure scripts so we needed to add that and regenerate
|
||||
the scripts as well.
|
||||
|
||||
Resolves: #193
|
||||
|
||||
- ### pjsip: Upgrade bundled version to pjproject 2.13.1
|
||||
Author: Stanislav Abramenkov
|
||||
Date: 2023-07-05
|
||||
|
||||
|
|
@ -0,0 +1,854 @@
|
|||
|
||||
Change Log for Release 20.4.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.4.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.3.1...20.4.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.4.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- app.h: Move declaration of ast_getdata_result before its first use
|
||||
- doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
- .github: Updates for AsteriskReleaser
|
||||
- app_voicemail: fix imap compilation errors
|
||||
- res_musiconhold: avoid moh state access on unlocked chan
|
||||
- utils: add lock timestamps for DEBUG_THREADS
|
||||
- .github: Back out triggering PROpenedOrUpdated by label
|
||||
- .github: Move publish docs to new file CreateDocs.yml
|
||||
- rest-api: Updates for new documentation site
|
||||
- .github: Remove result check from PROpenUpdateGateTests
|
||||
- .github: Fix use of 'contains'
|
||||
- .github: Add recheck label test to additional jobs
|
||||
- .github: Fix recheck label typos
|
||||
- .github: Fix recheck label manipulation
|
||||
- .github: Allow PR submit checks to be re-run by label
|
||||
- app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
- res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
- res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
- app_queue: Add force_longest_waiting_caller option.
|
||||
- pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
- res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
- configure: Remove obsolete and deprecated constructs.
|
||||
- res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
- ast-db-manage: Synchronize revisions between comments and code.
|
||||
- test_statis_endpoints: Fix channel_messages test again
|
||||
- res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
- tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
- AMI: Add parking position parameter to Park action
|
||||
- test_stasis_endpoints.c: Make channel_messages more stable
|
||||
- build: Fix a few gcc 13 issues
|
||||
- .github: Rework for merge approval
|
||||
- ast-db-manage: Fix alembic branching error caused by #122.
|
||||
- app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
- sounds: Update download URL to use HTTPS.
|
||||
- configure: Makefile downloader enable follow redirects.
|
||||
- res_musiconhold: Add option to loop last file.
|
||||
- chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
- AMI: Add CoreShowChannelMap action.
|
||||
- sig_analog: Add fuller Caller ID support.
|
||||
- res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
- app_queue: Preserve reason for realtime queues
|
||||
- .github: Fix issues with cherry-pick-reminder
|
||||
- indications: logging changes
|
||||
- .github Ignore error when adding reviewrs to PR
|
||||
- .github: Update field descriptions for AsteriskReleaser
|
||||
- callerid: Allow specifying timezone for date/time.
|
||||
- logrotate: Fix duplicate log entries.
|
||||
- chan_pjsip: Allow topology/session refreshes in early media state
|
||||
- chan_dahdi: Fix broken hidecallerid setting.
|
||||
- .github: Change title of AsteriskReleaser job
|
||||
- asterisk.c: Fix option warning for remote console.
|
||||
- .github: Don't add cherry-pick reminder if it's already present
|
||||
- .github: Fix quoting in PROpenedOrUpdated
|
||||
- .github: Add cherry-pick reminder to new PRs
|
||||
- configure: fix test code to match gethostbyname_r prototype.
|
||||
- res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
- res_sorcery_memory_cache.c: Fix memory leak
|
||||
- xml.c: Process XML Inclusions recursively.
|
||||
- .github: Tweak improvement issue type language.
|
||||
- .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
- .github: Fix staleness check to only run on certain labels.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### AMI: Add parking position parameter to Park action
|
||||
New ParkingSpace parameter has been added to AMI action Park.
|
||||
|
||||
- ### res_musiconhold: Add option to loop last file.
|
||||
The loop_last option in musiconhold.conf now
|
||||
allows the last file in the directory to be looped once reached.
|
||||
|
||||
- ### AMI: Add CoreShowChannelMap action.
|
||||
New AMI action CoreShowChannelMap has been added.
|
||||
|
||||
- ### sig_analog: Add fuller Caller ID support.
|
||||
Additional Caller ID properties are now supported on
|
||||
incoming calls to FXS stations, namely the
|
||||
redirecting reason and call qualifier.
|
||||
|
||||
- ### res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
When creating a bridge using the ARI the 'type' argument now
|
||||
accepts a new value 'sdp_label' which will configure the bridge to add
|
||||
labels for each stream in the SDP with the corresponding channel id.
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Make paused reason in realtime queues persist an
|
||||
Asterisk restart. This was fixed for non-realtime
|
||||
queues in ASTERISK_25732.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Add a new column to the queue_member table:
|
||||
reason_paused VARCHAR(80) so the reason can be preserved.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #45: [bug]: Non-bundled PJSIP check for evsub pending NOTIFY check is insufficient/ineffective
|
||||
- #55: [bug]: res_sorcery_memory_cache: Memory leak when calling sorcery_memory_cache_open
|
||||
- #64: [bug]: app_voicemail_imap wrong behavior when losing IMAP connection
|
||||
- #65: [bug]: heap overflow by default at startup
|
||||
- #66: [improvement]: Fix preserve reason of pause when Asterisk is restared for realtime queues
|
||||
- #73: [new-feature]: pjsip: Allow topology/session refreshes in early media state
|
||||
- #87: [bug]: app_followme: Setting enable_callee_prompt=no breaks timeout
|
||||
- #89: [improvement]: indications: logging changes
|
||||
- #91: [improvement]: Add parameter on ARI bridge create to allow it to send SDP labels
|
||||
- #94: [new-feature]: sig_analog: Add full Caller ID support for incoming calls
|
||||
- #96: [bug]: make install-logrotate causes logrotate to fail on service restart
|
||||
- #98: [new-feature]: callerid: Allow timezone to be specified at runtime
|
||||
- #100: [bug]: sig_analog: hidecallerid setting is broken
|
||||
- #102: [bug]: Strange warning - 'T' option is not compatible with remote console mode and has no effect.
|
||||
- #104: [improvement]: Add AMI action to get a list of connected channels
|
||||
- #108: [new-feature]: fair handling of calls in multi-queue scenarios
|
||||
- #110: [improvement]: utils - add lock timing information with DEBUG_THREADS
|
||||
- #116: [bug]: SIP Reason: "Call completed elsewhere" no longer propagating
|
||||
- #120: [bug]: chan_dahdi: Fix broken presentation for FXO caller ID
|
||||
- #122: [new-feature]: res_musiconhold: Add looplast option
|
||||
- #133: [bug]: unlock channel after moh state access
|
||||
- #136: [bug]: Makefile downloader does not follow redirects.
|
||||
- #145: [bug]: ABI issue with pjproject and pjsip_inv_session
|
||||
- #155: [bug]: GCC 13 is catching a few new trivial issues
|
||||
- #158: [bug]: test_stasis_endpoints.c: Unit test channel_messages is unstable
|
||||
- #174: [bug]: app_voicemail imap compile errors
|
||||
- #200: [bug]: Regression: In app.h an enum is used before its declaration.
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (2):
|
||||
- Update for 20.4.0-rc1
|
||||
- Update for 20.4.0-rc2
|
||||
|
||||
- ### Ben Ford (2):
|
||||
- AMI: Add CoreShowChannelMap action.
|
||||
- res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
|
||||
- ### George Joseph (23):
|
||||
- .github: Add cherry-pick reminder to new PRs
|
||||
- .github: Fix quoting in PROpenedOrUpdated
|
||||
- .github: Don't add cherry-pick reminder if it's already present
|
||||
- .github: Change title of AsteriskReleaser job
|
||||
- .github: Update field descriptions for AsteriskReleaser
|
||||
- .github Ignore error when adding reviewrs to PR
|
||||
- .github: Fix issues with cherry-pick-reminder
|
||||
- .github: Rework for merge approval
|
||||
- build: Fix a few gcc 13 issues
|
||||
- test_stasis_endpoints.c: Make channel_messages more stable
|
||||
- test_statis_endpoints: Fix channel_messages test again
|
||||
- .github: Allow PR submit checks to be re-run by label
|
||||
- .github: Fix recheck label manipulation
|
||||
- .github: Fix recheck label typos
|
||||
- .github: Add recheck label test to additional jobs
|
||||
- .github: Fix use of 'contains'
|
||||
- .github: Remove result check from PROpenUpdateGateTests
|
||||
- rest-api: Updates for new documentation site
|
||||
- .github: Move publish docs to new file CreateDocs.yml
|
||||
- .github: Back out triggering PROpenedOrUpdated by label
|
||||
- .github: Updates for AsteriskReleaser
|
||||
- doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
- app.h: Move declaration of ast_getdata_result before its first use
|
||||
|
||||
- ### Gitea (1):
|
||||
- .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
|
||||
- ### Jaco Kroon (2):
|
||||
- configure: fix test code to match gethostbyname_r prototype.
|
||||
- tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
|
||||
- ### Jiajian Zhou (1):
|
||||
- AMI: Add parking position parameter to Park action
|
||||
|
||||
- ### Joe Searle (1):
|
||||
- res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
|
||||
- ### Joshua C. Colp (2):
|
||||
- .github: Fix staleness check to only run on certain labels.
|
||||
- .github: Tweak improvement issue type language.
|
||||
|
||||
- ### Maximilian Fridrich (1):
|
||||
- chan_pjsip: Allow topology/session refreshes in early media state
|
||||
|
||||
- ### Miguel Angel Nubla (1):
|
||||
- configure: Makefile downloader enable follow redirects.
|
||||
|
||||
- ### Mike Bradeen (4):
|
||||
- indications: logging changes
|
||||
- utils: add lock timestamps for DEBUG_THREADS
|
||||
- res_musiconhold: avoid moh state access on unlocked chan
|
||||
- app_voicemail: fix imap compilation errors
|
||||
|
||||
- ### Nathan Bruning (1):
|
||||
- app_queue: Add force_longest_waiting_caller option.
|
||||
|
||||
- ### Naveen Albert (7):
|
||||
- asterisk.c: Fix option warning for remote console.
|
||||
- chan_dahdi: Fix broken hidecallerid setting.
|
||||
- logrotate: Fix duplicate log entries.
|
||||
- callerid: Allow specifying timezone for date/time.
|
||||
- sig_analog: Add fuller Caller ID support.
|
||||
- chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
- res_musiconhold: Add option to loop last file.
|
||||
|
||||
- ### Niklas Larsson (1):
|
||||
- app_queue: Preserve reason for realtime queues
|
||||
|
||||
- ### Olaf Titz (1):
|
||||
- app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
|
||||
- ### Sean Bright (10):
|
||||
- xml.c: Process XML Inclusions recursively.
|
||||
- res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
- sounds: Update download URL to use HTTPS.
|
||||
- ast-db-manage: Fix alembic branching error caused by #122.
|
||||
- res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
- ast-db-manage: Synchronize revisions between comments and code.
|
||||
- configure: Remove obsolete and deprecated constructs.
|
||||
- res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
- pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
- res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
|
||||
- ### alex2grad (1):
|
||||
- app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
|
||||
- ### zhengsh (1):
|
||||
- res_sorcery_memory_cache.c: Fix memory leak
|
||||
|
||||
- ### zhou_jiajian (1):
|
||||
- res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### app.h: Move declaration of ast_getdata_result before its first use
|
||||
Author: George Joseph
|
||||
Date: 2023-07-10
|
||||
|
||||
The ast_app_getdata() and ast_app_getdata_terminator() declarations
|
||||
in app.h were changed recently to return enum ast_getdata_result
|
||||
(which is how they were defined in app.c). The existing
|
||||
declaration of ast_getdata_result in app.h was about 1000 lines
|
||||
after those functions however so under certain circumstances,
|
||||
a "use before declaration" error was thrown by the compiler.
|
||||
The declaration of the enum was therefore moved to before those
|
||||
functions.
|
||||
|
||||
Resolves: #200
|
||||
|
||||
- ### doc: Remove obsolete CHANGES-staging and UPGRADE-staging
|
||||
Author: George Joseph
|
||||
Date: 2023-07-10
|
||||
|
||||
|
||||
- ### .github: Updates for AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-06-30
|
||||
|
||||
|
||||
- ### app_voicemail: fix imap compilation errors
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-26
|
||||
|
||||
Fixes two compilation errors in app_voicemail_imap, one due to an unsed
|
||||
variable and one due to a new variable added in the incorrect location
|
||||
in _163.
|
||||
|
||||
Resolves: #174
|
||||
|
||||
- ### res_musiconhold: avoid moh state access on unlocked chan
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-31
|
||||
|
||||
Move channel unlock to after moh state access to avoid
|
||||
potential unlocked access to state.
|
||||
|
||||
Resolves: #133
|
||||
|
||||
- ### utils: add lock timestamps for DEBUG_THREADS
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-23
|
||||
|
||||
Adds last locked and unlocked timestamps as well as a
|
||||
counter for the number of times the lock has been
|
||||
attempted (vs locked/unlocked) to debug output printed
|
||||
using the DEBUG_THREADS option.
|
||||
|
||||
Resolves: #110
|
||||
|
||||
- ### .github: Back out triggering PROpenedOrUpdated by label
|
||||
Author: George Joseph
|
||||
Date: 2023-06-29
|
||||
|
||||
|
||||
- ### .github: Move publish docs to new file CreateDocs.yml
|
||||
Author: George Joseph
|
||||
Date: 2023-06-27
|
||||
|
||||
|
||||
- ### rest-api: Updates for new documentation site
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
The new documentation site uses traditional markdown instead
|
||||
of the Confluence flavored version. This required changes in
|
||||
the mustache templates and the python that generates the files.
|
||||
|
||||
|
||||
- ### .github: Remove result check from PROpenUpdateGateTests
|
||||
Author: George Joseph
|
||||
Date: 2023-06-27
|
||||
|
||||
|
||||
- ### .github: Fix use of 'contains'
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Add recheck label test to additional jobs
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Fix recheck label typos
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Fix recheck label manipulation
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### .github: Allow PR submit checks to be re-run by label
|
||||
Author: George Joseph
|
||||
Date: 2023-06-26
|
||||
|
||||
|
||||
- ### app_voicemail_imap: Fix message count when IMAP server is unavailable
|
||||
Author: Olaf Titz
|
||||
Date: 2023-06-15
|
||||
|
||||
Some callers of __messagecount did not correctly handle error return,
|
||||
instead returning a -1 message count.
|
||||
This caused a notification with "Messages-Waiting: yes" and
|
||||
"Voice-Message: -1/0 (0/0)" if the IMAP server was unavailable.
|
||||
|
||||
Fixes: #64
|
||||
|
||||
- ### res_pjsip_rfc3326: Prefer Q.850 cause code over SIP.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-12
|
||||
|
||||
Resolves: #116
|
||||
|
||||
- ### res_pjsip_session: Added new function calls to avoid ABI issues.
|
||||
Author: Ben Ford
|
||||
Date: 2023-06-05
|
||||
|
||||
Added two new functions (ast_sip_session_get_dialog and
|
||||
ast_sip_session_get_pjsip_inv_state) that retrieve the dialog and the
|
||||
pjsip_inv_state respectively from the pjsip_inv_session on the
|
||||
ast_sip_session struct. This is due to pjproject adding a new field to
|
||||
the pjsip_inv_session struct that caused crashes when trying to access
|
||||
fields that were no longer where they were expected to be if a module
|
||||
was compiled against a different version of pjproject.
|
||||
|
||||
Resolves: #145
|
||||
|
||||
- ### app_queue: Add force_longest_waiting_caller option.
|
||||
Author: Nathan Bruning
|
||||
Date: 2023-01-24
|
||||
|
||||
This adds an option 'force_longest_waiting_caller' which changes the
|
||||
global behavior of the queue engine to prevent queue callers from
|
||||
'jumping ahead' when an agent is in multiple queues.
|
||||
|
||||
Resolves: #108
|
||||
|
||||
Also closes old asterisk issues:
|
||||
- ASTERISK-17732
|
||||
- ASTERISK-17570
|
||||
|
||||
|
||||
- ### pjsip_transport_events.c: Use %zu printf specifier for size_t.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Partially resolves #143.
|
||||
|
||||
|
||||
- ### res_crypto.c: Gracefully handle potential key filename truncation.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Partially resolves #143.
|
||||
|
||||
|
||||
- ### configure: Remove obsolete and deprecated constructs.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-01
|
||||
|
||||
These were uncovered when trying to run `bootstrap.sh` with Autoconf
|
||||
2.71:
|
||||
|
||||
* AC_CONFIG_HEADER() is deprecated in favor of AC_CONFIG_HEADERS().
|
||||
* AC_HEADER_TIME is obsolete.
|
||||
* $as_echo is deprecated in favor of AS_ECHO() which requires an update
|
||||
to ax_pthread.m4.
|
||||
|
||||
Note that the generated artifacts in this commit are from Autoconf 2.69.
|
||||
|
||||
Resolves #139
|
||||
|
||||
|
||||
- ### res_fax_spandsp.c: Clean up a spaces/tabs issue
|
||||
Author: zhou_jiajian
|
||||
Date: 2023-05-26
|
||||
|
||||
|
||||
- ### ast-db-manage: Synchronize revisions between comments and code.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-06
|
||||
|
||||
In a handful of migrations, the comment header that indicates the
|
||||
current and previous revisions has drifted from the identifiers
|
||||
revision and down_revision variables. This updates the comment headers
|
||||
to match the code.
|
||||
|
||||
|
||||
- ### test_statis_endpoints: Fix channel_messages test again
|
||||
Author: George Joseph
|
||||
Date: 2023-06-12
|
||||
|
||||
|
||||
- ### res_crypto.c: Avoid using the non-portable ALLPERMS macro.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
ALLPERMS is not POSIX and it's trivial enough to not jump through
|
||||
autoconf hoops to check for it.
|
||||
|
||||
Fixes #149.
|
||||
|
||||
|
||||
- ### tcptls: when disabling a server port, we should set the accept_fd to -1.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-06-02
|
||||
|
||||
If we don't set this to -1 if the structure can be potentially re-used
|
||||
later then it's possible that we'll issue a close() on an unrelated file
|
||||
descriptor, breaking asterisk in other interesting ways.
|
||||
|
||||
I believe this to be an unlikely scenario, but it costs nothing to be
|
||||
safe.
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### AMI: Add parking position parameter to Park action
|
||||
Author: Jiajian Zhou
|
||||
Date: 2023-05-19
|
||||
|
||||
Add a parking space extension parameter (ParkingSpace) to the Park action.
|
||||
Park action will attempt to park the call to that extension.
|
||||
If the extension is already in use, then execution will continue at the next priority.
|
||||
|
||||
UserNote: New ParkingSpace parameter has been added to AMI action Park.
|
||||
|
||||
- ### test_stasis_endpoints.c: Make channel_messages more stable
|
||||
Author: George Joseph
|
||||
Date: 2023-06-09
|
||||
|
||||
The channel_messages test was assuming that stasis would return
|
||||
messages in a specific order. This is an incorrect assumption as
|
||||
message ordering was never guaranteed. This was causing the test
|
||||
to fail occasionally. We now test all the messages for the
|
||||
required message types instead of testing one by one.
|
||||
|
||||
Resolves: #158
|
||||
|
||||
- ### build: Fix a few gcc 13 issues
|
||||
Author: George Joseph
|
||||
Date: 2023-06-09
|
||||
|
||||
* gcc 13 is now catching when a function is declared as returning
|
||||
an enum but defined as returning an int or vice versa. Fixed
|
||||
a few in app.h, loader.c, stasis_message.c.
|
||||
|
||||
* gcc 13 is also now (incorrectly) complaining of dangling pointers
|
||||
when assigning a pointer to a local char array to a char *. Had
|
||||
to change that to an ast_alloca.
|
||||
|
||||
Resolves: #155
|
||||
|
||||
- ### .github: Rework for merge approval
|
||||
Author: George Joseph
|
||||
Date: 2023-06-06
|
||||
|
||||
|
||||
- ### ast-db-manage: Fix alembic branching error caused by #122.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-05
|
||||
|
||||
Fixes #147.
|
||||
|
||||
|
||||
- ### app_followme: fix issue with enable_callee_prompt=no (#88)
|
||||
Author: alex2grad
|
||||
Date: 2023-06-05
|
||||
|
||||
* app_followme: fix issue with enable_callee_prompt=no
|
||||
|
||||
If the FollowMe option 'enable_callee_prompt' is set to 'no' then Asterisk
|
||||
incorrectly sets a winner channel to the channel from which any control frame was read.
|
||||
|
||||
This fix sets the winner channel only to the answered channel.
|
||||
|
||||
Resolves: #87
|
||||
|
||||
ASTERISK-30326
|
||||
|
||||
|
||||
- ### sounds: Update download URL to use HTTPS.
|
||||
Author: Sean Bright
|
||||
Date: 2023-06-01
|
||||
|
||||
Related to #136
|
||||
|
||||
|
||||
- ### configure: Makefile downloader enable follow redirects.
|
||||
Author: Miguel Angel Nubla
|
||||
Date: 2023-06-01
|
||||
|
||||
If curl is used for building, any download such as a sounds package
|
||||
will fail to follow HTTP redirects and will download wrong data.
|
||||
|
||||
Resolves: #136
|
||||
|
||||
- ### res_musiconhold: Add option to loop last file.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-25
|
||||
|
||||
Adds the loop_last option to res_musiconhold,
|
||||
which allows the last audio file in the directory
|
||||
to be looped perpetually once reached, rather than
|
||||
circling back to the beginning again.
|
||||
|
||||
Resolves: #122
|
||||
ASTERISK-30462
|
||||
|
||||
UserNote: The loop_last option in musiconhold.conf now
|
||||
allows the last file in the directory to be looped once reached.
|
||||
|
||||
|
||||
- ### chan_dahdi: Fix Caller ID presentation for FXO ports.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-25
|
||||
|
||||
Currently, the presentation for incoming channels is
|
||||
always available, because it is never actually set,
|
||||
meaning the channel presentation can be nonsensical.
|
||||
If the presentation from the incoming Caller ID spill
|
||||
is private or unavailable, we now update the channel
|
||||
presentation to reflect this.
|
||||
|
||||
Resolves: #120
|
||||
ASTERISK-30333
|
||||
ASTERISK-21741
|
||||
|
||||
|
||||
- ### AMI: Add CoreShowChannelMap action.
|
||||
Author: Ben Ford
|
||||
Date: 2023-05-18
|
||||
|
||||
Adds a new AMI action (CoreShowChannelMap) that takes in a channel name
|
||||
and provides a list of all channels that are connected to that channel,
|
||||
following local channel connections as well.
|
||||
|
||||
Resolves: #104
|
||||
|
||||
UserNote: New AMI action CoreShowChannelMap has been added.
|
||||
|
||||
- ### sig_analog: Add fuller Caller ID support.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
A previous change, ASTERISK_29991, made it possible
|
||||
to send additional Caller ID parameters that were
|
||||
not previously supported.
|
||||
|
||||
This change adds support for analog DAHDI channels
|
||||
to now be able to receive these parameters for
|
||||
on-hook Caller ID, in order to enhance the usability
|
||||
of CPE that support these parameters.
|
||||
|
||||
Resolves: #94
|
||||
ASTERISK-30331
|
||||
|
||||
UserNote: Additional Caller ID properties are now supported on
|
||||
incoming calls to FXS stations, namely the
|
||||
redirecting reason and call qualifier.
|
||||
|
||||
|
||||
- ### res_stasis.c: Add new type 'sdp_label' for bridge creation.
|
||||
Author: Joe Searle
|
||||
Date: 2023-05-25
|
||||
|
||||
Add new type 'sdp_label' when creating a bridge using the ARI. This will
|
||||
add labels to the SDP for each stream, the label is set to the
|
||||
corresponding channel id.
|
||||
|
||||
Resolves: #91
|
||||
|
||||
UserNote: When creating a bridge using the ARI the 'type' argument now
|
||||
accepts a new value 'sdp_label' which will configure the bridge to add
|
||||
labels for each stream in the SDP with the corresponding channel id.
|
||||
|
||||
|
||||
- ### app_queue: Preserve reason for realtime queues
|
||||
Author: Niklas Larsson
|
||||
Date: 2023-05-05
|
||||
|
||||
When Asterisk is restarted it does not preserve paused reason for
|
||||
members of realtime queues. This was fixed for non-realtime queues in
|
||||
ASTERISK_25732
|
||||
|
||||
Resolves: #66
|
||||
|
||||
UpgradeNote: Add a new column to the queue_member table:
|
||||
reason_paused VARCHAR(80) so the reason can be preserved.
|
||||
|
||||
UserNote: Make paused reason in realtime queues persist an
|
||||
Asterisk restart. This was fixed for non-realtime
|
||||
queues in ASTERISK_25732.
|
||||
|
||||
|
||||
- ### .github: Fix issues with cherry-pick-reminder
|
||||
Author: George Joseph
|
||||
Date: 2023-06-05
|
||||
|
||||
|
||||
- ### indications: logging changes
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-05-16
|
||||
|
||||
Increase verbosity to indicate failure due to missing country
|
||||
and to specify default on CLI dump
|
||||
|
||||
Resolves: #89
|
||||
|
||||
- ### .github Ignore error when adding reviewrs to PR
|
||||
Author: George Joseph
|
||||
Date: 2023-06-05
|
||||
|
||||
|
||||
- ### .github: Update field descriptions for AsteriskReleaser
|
||||
Author: George Joseph
|
||||
Date: 2023-05-26
|
||||
|
||||
|
||||
- ### callerid: Allow specifying timezone for date/time.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The Caller ID generation routine currently is hardcoded
|
||||
to always use the system time zone. This makes it possible
|
||||
to optionally specify any TZ-format time zone.
|
||||
|
||||
Resolves: #98
|
||||
ASTERISK-30330
|
||||
|
||||
|
||||
- ### logrotate: Fix duplicate log entries.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The Asterisk logrotate script contains explicit
|
||||
references to files with the .log extension,
|
||||
which are also included when *log is expanded.
|
||||
This causes issues with newer versions of logrotate.
|
||||
This fixes this by ensuring that a log file cannot
|
||||
be referenced multiple times after expansion occurs.
|
||||
|
||||
Resolves: #96
|
||||
ASTERISK-30442
|
||||
Reported by: EN Barnett
|
||||
Tested by: EN Barnett
|
||||
|
||||
|
||||
- ### chan_pjsip: Allow topology/session refreshes in early media state
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-10
|
||||
|
||||
With this change, session modifications in the early media state are
|
||||
possible if the SDP was sent reliably and confirmed by a PRACK. For
|
||||
details, see RFC 6337, escpecially section 3.2.
|
||||
|
||||
Resolves: #73
|
||||
|
||||
- ### chan_dahdi: Fix broken hidecallerid setting.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
The hidecallerid setting in chan_dahdi.conf currently
|
||||
is broken for a couple reasons.
|
||||
|
||||
First, the actual code in sig_analog to "allow" or "block"
|
||||
Caller ID depending on this setting improperly used
|
||||
ast_set_callerid instead of updating the presentation.
|
||||
This issue was mostly fixed in ASTERISK_29991, and that
|
||||
fix is carried forward to this code as well.
|
||||
|
||||
Secondly, the hidecallerid setting is set on the DAHDI
|
||||
pvt but not carried forward to the analog pvt properly.
|
||||
This is because the chan_dahdi config loading code improperly
|
||||
set permhidecallerid to permhidecallerid from the config file,
|
||||
even though hidecallerid is what is actually set from the config
|
||||
file. (This is done correctly for call waiting, a few lines above.)
|
||||
This is fixed to read the proper value.
|
||||
|
||||
Thirdly, in sig_analog, hidecallerid is set to permhidecallerid
|
||||
only on hangup. This can lead to potential security vulnerabilities
|
||||
as an allowed Caller ID from an initial call can "leak" into subsequent
|
||||
calls if no hangup occurs between them. This is fixed by setting
|
||||
hidecallerid to permcallerid when calls begin, rather than when they end.
|
||||
This also means we don't need to also set hidecallerid in chan_dahdi.c
|
||||
when copying from the config, as we would have to otherwise.
|
||||
|
||||
Fourthly, sig_analog currently only allows dialing *67 or *82 if
|
||||
that would actually toggle the presentation. A comment is added
|
||||
clarifying that this behavior is okay.
|
||||
|
||||
Finally, a couple log messages are updated to be more accurate.
|
||||
|
||||
Resolves: #100
|
||||
ASTERISK-30349 #close
|
||||
|
||||
|
||||
- ### .github: Change title of AsteriskReleaser job
|
||||
Author: George Joseph
|
||||
Date: 2023-05-23
|
||||
|
||||
|
||||
- ### asterisk.c: Fix option warning for remote console.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-05-18
|
||||
|
||||
Commit 09e989f972e2583df4e9bf585c246c37322d8d2f
|
||||
categorized the T option as not being compatible
|
||||
with remote consoles, but they do affect verbose
|
||||
messages with remote console. This fixes this.
|
||||
|
||||
Resolves: #102
|
||||
|
||||
- ### .github: Don't add cherry-pick reminder if it's already present
|
||||
Author: George Joseph
|
||||
Date: 2023-05-22
|
||||
|
||||
|
||||
- ### .github: Fix quoting in PROpenedOrUpdated
|
||||
Author: George Joseph
|
||||
Date: 2023-05-16
|
||||
|
||||
|
||||
- ### .github: Add cherry-pick reminder to new PRs
|
||||
Author: George Joseph
|
||||
Date: 2023-05-15
|
||||
|
||||
|
||||
- ### configure: fix test code to match gethostbyname_r prototype.
|
||||
Author: Jaco Kroon
|
||||
Date: 2023-05-10
|
||||
|
||||
This enables the test to work with CC=clang.
|
||||
|
||||
Without this the test for 6 args would fail with:
|
||||
|
||||
utils.c:99:12: error: static declaration of 'gethostbyname_r' follows non-static declaration
|
||||
static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
|
||||
^
|
||||
/usr/include/netdb.h:177:12: note: previous declaration is here
|
||||
extern int gethostbyname_r (const char *__restrict __name,
|
||||
^
|
||||
|
||||
Fixing the expected return type to int sorts this out.
|
||||
|
||||
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
|
||||
|
||||
- ### res_pjsip_pubsub.c: Use pjsip version for pending NOTIFY check. (#77)
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-11
|
||||
|
||||
The functionality we are interested in is present only in pjsip 2.13
|
||||
and newer.
|
||||
|
||||
Resolves: #45
|
||||
|
||||
- ### res_sorcery_memory_cache.c: Fix memory leak
|
||||
Author: zhengsh
|
||||
Date: 2023-05-03
|
||||
|
||||
Replace the original call to ast_strdup with a call to ast_strdupa to fix the leak issue.
|
||||
|
||||
Resolves: #55
|
||||
ASTERISK-30429
|
||||
|
||||
|
||||
- ### xml.c: Process XML Inclusions recursively.
|
||||
Author: Sean Bright
|
||||
Date: 2023-05-09
|
||||
|
||||
If processing an XInclude results in new <xi:include> elements, we
|
||||
need to run XInclude processing again. This continues until no
|
||||
replacement occurs or an error is encountered.
|
||||
|
||||
There is a separate issue with dynamic strings (ast_str) that will be
|
||||
addressed separately.
|
||||
|
||||
Resolves: #65
|
||||
|
||||
- ### .github: Tweak improvement issue type language.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Tweak new feature language, and move feature requests elsewhere.
|
||||
Author: Gitea
|
||||
Date: 2023-05-09
|
||||
|
||||
|
||||
- ### .github: Fix staleness check to only run on certain labels.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-05-09
|
||||
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.4.0...20.5.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix broken documentation anchors
|
||||
- res_pjsip_session: Send Session Interval too small response
|
||||
- .github: Update workflow-application-token-action to v2
|
||||
- app_dial: Fix infinite loop when sending digits.
|
||||
- app_voicemail: Fix for loop declarations
|
||||
- alembic: Fix quoting of the 100rel column
|
||||
- pbx.c: Fix gcc 12 compiler warning.
|
||||
- app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
- download_externals: Fix a few version related issues
|
||||
- main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
- sig_analog: Add Called Subscriber Held capability.
|
||||
- app_macro: Fix locking around datastore access
|
||||
- Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
- .github: Use generic releaser
|
||||
- install_prereq: Fix dependency install on aarch64.
|
||||
- res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
- extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
- rest-api: Run make ari-stubs
|
||||
- res_pjsip_header_funcs: Make prefix argument optional.
|
||||
- pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
- manager: Tolerate stasis messages with no channel snapshot.
|
||||
- core/ari/pjsip: Add refer mechanism
|
||||
- chan_dahdi: Allow autoreoriginating after hangup.
|
||||
- audiohook: Unlock channel in mute if no audiohooks present.
|
||||
- sig_analog: Allow three-way flash to time out to silence.
|
||||
- res_prometheus: Do not generate broken metrics
|
||||
- res_pjsip: Enable TLS v1.3 if present.
|
||||
- func_cut: Add example to documentation.
|
||||
- extensions.conf.sample: Remove reference to missing context.
|
||||
- func_export: Use correct function argument as variable name.
|
||||
- app_queue: Add support for applying caller priority change immediately.
|
||||
- .github: Fix cherry-pick reminder issues
|
||||
- chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
- res_geolocation: Ensure required 'location_info' is present.
|
||||
- Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
- app_voicemail: add CLI commands for message manipulation
|
||||
- res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
- .github: Minor tweak to Asterisk Releaser
|
||||
- .github: Suppress cherry-pick reminder for some situations
|
||||
- sig_analog: Allow immediate fake ring to be suppressed.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### sig_analog: Add Called Subscriber Held capability.
|
||||
Called Subscriber Held is now supported for analog
|
||||
FXS channels, using the calledsubscriberheld option. This allows
|
||||
a station user to go on hook when receiving an incoming call
|
||||
and resume from another phone on the same line by going on hook,
|
||||
without disconnecting the call.
|
||||
|
||||
- ### res_pjsip_header_funcs: Make prefix argument optional.
|
||||
The prefix argument to PJSIP_HEADERS is now
|
||||
optional. If not specified, all header names will be
|
||||
returned.
|
||||
|
||||
- ### core/ari/pjsip: Add refer mechanism
|
||||
There is a new ARI endpoint `/endpoints/refer` for referring
|
||||
an endpoint to some URI or endpoint.
|
||||
|
||||
- ### chan_dahdi: Allow autoreoriginating after hangup.
|
||||
The autoreoriginate setting now allows for kewlstart FXS
|
||||
channels to automatically reoriginate and provide dial tone to the
|
||||
user again after all calls on the line have cleared. This saves users
|
||||
from having to manually hang up and pick up the receiver again before
|
||||
making another call.
|
||||
|
||||
- ### sig_analog: Allow three-way flash to time out to silence.
|
||||
The threewaysilenthold option now allows the three-way
|
||||
dial tone to time out to silence, rather than continuing forever.
|
||||
|
||||
- ### res_pjsip: Enable TLS v1.3 if present.
|
||||
res_pjsip now allows TLS v1.3 to be enabled if supported by
|
||||
the underlying PJSIP library. The bundled version of PJSIP supports
|
||||
TLS v1.3.
|
||||
|
||||
- ### app_queue: Add support for applying caller priority change immediately.
|
||||
The 'queue priority caller' CLI command and
|
||||
'QueueChangePriorityCaller' AMI action now have an 'immediate'
|
||||
argument which allows the caller priority change to be reflected
|
||||
immediately, causing the position of a caller to move within the
|
||||
queue depending on the priorities of the other callers.
|
||||
|
||||
- ### Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
The following manager actions have been added
|
||||
VoicemailBoxSummary - Generate message list for a given mailbox
|
||||
VoicemailRemove - Remove a message from a mailbox folder
|
||||
VoicemailMove - Move a message from one folder to another within a mailbox
|
||||
VoicemailForward - Copy a message from one folder in one mailbox
|
||||
to another folder in another or the same mailbox.
|
||||
|
||||
- ### app_voicemail: add CLI commands for message manipulation
|
||||
The following CLI commands have been added to app_voicemail
|
||||
voicemail show mailbox <mailbox> <context>
|
||||
Show contents of mailbox <mailbox>@<context>
|
||||
voicemail remove <mailbox> <context> <from_folder> <messageid>
|
||||
Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>
|
||||
voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>
|
||||
Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>
|
||||
voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>
|
||||
Forward message <messageid> in mailbox <mailbox>@<context> <from_folder> to
|
||||
mailbox <mailbox>@<context> <to_folder>
|
||||
|
||||
- ### sig_analog: Allow immediate fake ring to be suppressed.
|
||||
The immediatering option can now be set to no to suppress
|
||||
the fake audible ringback provided when immediate=yes on FXS channels.
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #37: [Bug]: contrib/scripts/install_prereq tries to install armhf packages on aarch64 Debian platforms
|
||||
- #71: [new-feature]: core/ari/pjsip: Add refer mechanism to refer endpoints to some resource
|
||||
- #118: [new-feature]: chan_dahdi: Allow fake ringing to be inhibited when immediate=yes
|
||||
- #170: [improvement]: app_voicemail - add CLI commands to manipulate messages
|
||||
- #179: [bug]: Queue strategy “Linear” with Asterisk 20 on Realtime
|
||||
- #181: [improvement]: app_voicemail - add manager actions to display and manipulate messages
|
||||
- #202: [improvement]: app_queue: Add support for immediately applying queue caller priority change
|
||||
- #205: [new-feature]: sig_analog: Allow flash to time out to silent hold
|
||||
- #224: [new-feature]: chan_dahdi: Allow automatic reorigination on hangup
|
||||
- #226: [improvement]: Apply contact_user to incoming calls
|
||||
- #230: [bug]: PJSIP_RESPONSE_HEADERS function documentation is misleading
|
||||
- #233: [bug]: Deadlock with MixMonitorMute AMI action
|
||||
- #240: [new-feature]: sig_analog: Add Called Subscriber Held capability
|
||||
- #253: app_gosub patch appear to have broken predial handlers that utilize macros that call gosubs
|
||||
- #255: [bug]: pjsip_endpt_register_module: Assertion "Too many modules registered"
|
||||
- #263: [bug]: download_externals doesn't always handle versions correctly
|
||||
- #265: [bug]: app_macro isn't locking around channel datastore access
|
||||
- #267: [bug]: ari: refer with display_name key in request body leads to crash
|
||||
- #274: [bug]: Syntax Error in SQL Code
|
||||
- #275: [bug]:Asterisk make now requires ASTCFLAGS='-std=gnu99 -Wdeclaration-after-statement'
|
||||
- #277: [bug]: pbx.c: Compiler error with gcc 12.2
|
||||
- #281: [bug]: app_dial: Infinite loop if called channel hangs up while receiving digits
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Asterisk Development Team (1):
|
||||
- Update for 20.5.0-rc1
|
||||
|
||||
- ### Bastian Triller (1):
|
||||
- res_pjsip_session: Send Session Interval too small response
|
||||
|
||||
- ### George Joseph (12):
|
||||
- .github: Suppress cherry-pick reminder for some situations
|
||||
- .github: Minor tweak to Asterisk Releaser
|
||||
- .github: Fix cherry-pick reminder issues
|
||||
- pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
- rest-api: Run make ari-stubs
|
||||
- .github: Use generic releaser
|
||||
- download_externals: Fix a few version related issues
|
||||
- alembic: Fix quoting of the 100rel column
|
||||
- .github: Update workflow-application-token-action to v2
|
||||
- ari-stubs: Fix broken documentation anchors
|
||||
- ari-stubs: Fix more local anchor references
|
||||
- ari-stubs: Fix more local anchor references
|
||||
|
||||
- ### Holger Hans Peter Freyther (1):
|
||||
- res_prometheus: Do not generate broken metrics
|
||||
|
||||
- ### Jason D. McCormick (1):
|
||||
- install_prereq: Fix dependency install on aarch64.
|
||||
|
||||
- ### Joshua C. Colp (3):
|
||||
- app_queue: Add support for applying caller priority change immediately.
|
||||
- audiohook: Unlock channel in mute if no audiohooks present.
|
||||
- manager: Tolerate stasis messages with no channel snapshot.
|
||||
|
||||
- ### Matthew Fredrickson (2):
|
||||
- Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
- app_macro: Fix locking around datastore access
|
||||
|
||||
- ### Maximilian Fridrich (2):
|
||||
- core/ari/pjsip: Add refer mechanism
|
||||
- main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
|
||||
- ### Mike Bradeen (3):
|
||||
- app_voicemail: add CLI commands for message manipulation
|
||||
- Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
- app_voicemail: Fix for loop declarations
|
||||
|
||||
- ### MikeNaso (1):
|
||||
- res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
|
||||
- ### Naveen Albert (7):
|
||||
- sig_analog: Allow immediate fake ring to be suppressed.
|
||||
- sig_analog: Allow three-way flash to time out to silence.
|
||||
- chan_dahdi: Allow autoreoriginating after hangup.
|
||||
- res_pjsip_header_funcs: Make prefix argument optional.
|
||||
- sig_analog: Add Called Subscriber Held capability.
|
||||
- pbx.c: Fix gcc 12 compiler warning.
|
||||
- app_dial: Fix infinite loop when sending digits.
|
||||
|
||||
- ### Sean Bright (6):
|
||||
- res_geolocation: Ensure required 'location_info' is present.
|
||||
- chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
- func_export: Use correct function argument as variable name.
|
||||
- extensions.conf.sample: Remove reference to missing context.
|
||||
- res_pjsip: Enable TLS v1.3 if present.
|
||||
- extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
|
||||
- ### phoneben (1):
|
||||
- func_cut: Add example to documentation.
|
||||
|
||||
- ### zhengsh (2):
|
||||
- res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
- app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### ari-stubs: Fix more local anchor references
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
Also allow CreateDocs job to be run manually with default branches.
|
||||
|
||||
|
||||
- ### ari-stubs: Fix more local anchor references
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
Also allow CreateDocs job to be run manually with default branches.
|
||||
|
||||
|
||||
- ### ari-stubs: Fix broken documentation anchors
|
||||
Author: George Joseph
|
||||
Date: 2023-09-05
|
||||
|
||||
All of the links that reference page anchors with capital letters in
|
||||
the ids (#Something) have been changed to lower case to match the
|
||||
anchors that are generated by mkdocs.
|
||||
|
||||
|
||||
- ### res_pjsip_session: Send Session Interval too small response
|
||||
Author: Bastian Triller
|
||||
Date: 2023-08-28
|
||||
|
||||
Handle session interval lower than endpoint's configured minimum timer
|
||||
when sending first answer. Timer setting is checked during this step and
|
||||
needs to handled appropriately.
|
||||
Before this change, no response was sent at all. After this change a
|
||||
response with 422 Session Interval too small is sent to UAC.
|
||||
|
||||
|
||||
- ### .github: Update workflow-application-token-action to v2
|
||||
Author: George Joseph
|
||||
Date: 2023-08-31
|
||||
|
||||
|
||||
- ### app_dial: Fix infinite loop when sending digits.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-28
|
||||
|
||||
If the called party hangs up while digits are being
|
||||
sent, -1 is returned to indicate so, but app_dial
|
||||
was not checking the return value, resulting in
|
||||
the hangup being lost and looping forever until
|
||||
the caller manually hangs up the channel. We now
|
||||
abort if digit sending fails.
|
||||
|
||||
ASTERISK-29428 #close
|
||||
|
||||
Resolves: #281
|
||||
|
||||
- ### app_voicemail: Fix for loop declarations
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-08-29
|
||||
|
||||
Resolve for loop initial declarations added in cli changes.
|
||||
|
||||
Resolves: #275
|
||||
|
||||
- ### alembic: Fix quoting of the 100rel column
|
||||
Author: George Joseph
|
||||
Date: 2023-08-28
|
||||
|
||||
Add quoting around the ps_endpoints 100rel column in the ALTER
|
||||
statements. Although alembic doesn't complain when generating
|
||||
sql statements, postgresql does (rightly so).
|
||||
|
||||
Resolves: #274
|
||||
|
||||
- ### pbx.c: Fix gcc 12 compiler warning.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-27
|
||||
|
||||
Resolves: #277
|
||||
|
||||
- ### app_audiosocket: Fixed timeout with -1 to avoid busy loop.
|
||||
Author: zhengsh
|
||||
Date: 2023-08-24
|
||||
|
||||
Resolves: asterisk#234
|
||||
|
||||
- ### download_externals: Fix a few version related issues
|
||||
Author: George Joseph
|
||||
Date: 2023-08-18
|
||||
|
||||
* Fixed issue with the script not parsing the new tag format for
|
||||
certified releases. The format changed from certified/18.9-cert5
|
||||
to certified-18.9-cert5.
|
||||
|
||||
* Fixed issue where the asterisk version wasn't being considered
|
||||
when looking for cached versions.
|
||||
|
||||
Resolves: #263
|
||||
|
||||
- ### main/refer.c: Fix double free in refer_data_destructor + potential leak
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-08-21
|
||||
|
||||
Resolves: #267
|
||||
|
||||
- ### sig_analog: Add Called Subscriber Held capability.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-09
|
||||
|
||||
This adds support for Called Subscriber Held for FXS
|
||||
lines, which allows users to go on hook when receiving
|
||||
a call and resume the call later from another phone on
|
||||
the same line, without disconnecting the call. This is
|
||||
a convenience mechanism that most real PSTN telephone
|
||||
switches support.
|
||||
|
||||
ASTERISK-30372 #close
|
||||
|
||||
Resolves: #240
|
||||
|
||||
UserNote: Called Subscriber Held is now supported for analog
|
||||
FXS channels, using the calledsubscriberheld option. This allows
|
||||
a station user to go on hook when receiving an incoming call
|
||||
and resume from another phone on the same line by going on hook,
|
||||
without disconnecting the call.
|
||||
|
||||
|
||||
- ### app_macro: Fix locking around datastore access
|
||||
Author: Matthew Fredrickson
|
||||
Date: 2023-08-21
|
||||
|
||||
app_macro sometimes would crash due to datastore list corruption on the
|
||||
channel because of lack of locking around find and create process for
|
||||
the macro datastore. This patch locks the channel lock prior to protect
|
||||
against this problem.
|
||||
|
||||
Resolves: #265
|
||||
|
||||
- ### Revert "app_stack: Print proper exit location for PBXless channels."
|
||||
Author: Matthew Fredrickson
|
||||
Date: 2023-08-10
|
||||
|
||||
This reverts commit 617dad4cba1513dddce87b8e95a61415fb587cf1.
|
||||
|
||||
apps/app_stack.c: Revert buggy gosub patch
|
||||
|
||||
This seems to break the case when a predial macro calls a gosub.
|
||||
When the gosub calls return, the Return function outputs:
|
||||
|
||||
app_stack.c:423 return_exec: Return without Gosub: stack is empty
|
||||
|
||||
This returns -1 to the calling macro, which returns to app_dial
|
||||
and causes the call to hangup instead of proceeding with the macro
|
||||
that invoked the gosub.
|
||||
|
||||
Resolves: #253
|
||||
|
||||
- ### .github: Use generic releaser
|
||||
Author: George Joseph
|
||||
Date: 2023-08-15
|
||||
|
||||
|
||||
- ### install_prereq: Fix dependency install on aarch64.
|
||||
Author: Jason D. McCormick
|
||||
Date: 2023-04-28
|
||||
|
||||
Fixes dependency solutions in install_prereq for Debian aarch64
|
||||
platforms. install_prereq was attempting to forcibly install 32-bit
|
||||
armhf packages due to the aptitude search for dependencies.
|
||||
|
||||
Resolves: #37
|
||||
|
||||
- ### res_pjsip.c: Set contact_user on incoming call local Contact header
|
||||
Author: MikeNaso
|
||||
Date: 2023-08-08
|
||||
|
||||
If the contact_user is configured on the endpoint it will now be set on the local Contact header URI for incoming calls. The contact_user has already been set on the local Contact header URI for outgoing calls.
|
||||
|
||||
Resolves: #226
|
||||
|
||||
- ### extconfig: Allow explicit DB result set ordering to be disabled.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-12
|
||||
|
||||
Added a new boolean configuration flag -
|
||||
`order_multi_row_results_by_initial_column` - to both res_pgsql.conf
|
||||
and res_config_odbc.conf that allows the administrator to disable the
|
||||
explicit `ORDER BY` that was previously being added to all generated
|
||||
SQL statements that returned multiple rows.
|
||||
|
||||
Fixes: #179
|
||||
|
||||
- ### rest-api: Run make ari-stubs
|
||||
Author: George Joseph
|
||||
Date: 2023-08-09
|
||||
|
||||
An earlier cherry-pick that involved rest-api somehow didn't include
|
||||
a comment change in res/ari/resource_endpoints.h. This commit
|
||||
corrects that. No changes other than the comment.
|
||||
|
||||
|
||||
- ### res_pjsip_header_funcs: Make prefix argument optional.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-09
|
||||
|
||||
The documentation for PJSIP_HEADERS claims that
|
||||
prefix is optional, but in the code it is actually not.
|
||||
However, there is no inherent reason for this, as users
|
||||
may want to retrieve all header names, not just those
|
||||
beginning with a certain prefix.
|
||||
|
||||
This makes the prefix optional for this function,
|
||||
simply fetching all header names if not specified.
|
||||
As a result, the documentation is now correct.
|
||||
|
||||
Resolves: #230
|
||||
|
||||
UserNote: The prefix argument to PJSIP_HEADERS is now
|
||||
optional. If not specified, all header names will be
|
||||
returned.
|
||||
|
||||
|
||||
- ### pjproject_bundled: Increase PJSIP_MAX_MODULE to 38
|
||||
Author: George Joseph
|
||||
Date: 2023-08-11
|
||||
|
||||
The default is 32 with 8 being used by pjproject itself. Recent
|
||||
commits have put us over the limit resulting in assertions in
|
||||
pjproject. Since this value is used in invites, dialogs,
|
||||
transports and subscriptions as well as the global pjproject
|
||||
endpoint, we don't want to increase it too much.
|
||||
|
||||
Resolves: #255
|
||||
|
||||
- ### manager: Tolerate stasis messages with no channel snapshot.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-08-09
|
||||
|
||||
In some cases I have yet to determine some stasis messages may
|
||||
be created without a channel snapshot. This change adds some
|
||||
tolerance to this scenario, preventing a crash from occurring.
|
||||
|
||||
|
||||
- ### core/ari/pjsip: Add refer mechanism
|
||||
Author: Maximilian Fridrich
|
||||
Date: 2023-05-10
|
||||
|
||||
This change adds support for refers that are not session based. It
|
||||
includes a refer implementation for the PJSIP technology which results
|
||||
in out-of-dialog REFERs being sent to a PJSIP endpoint. These can be
|
||||
triggered using the new ARI endpoint `/endpoints/refer`.
|
||||
|
||||
Resolves: #71
|
||||
|
||||
UserNote: There is a new ARI endpoint `/endpoints/refer` for referring
|
||||
an endpoint to some URI or endpoint.
|
||||
|
||||
|
||||
- ### chan_dahdi: Allow autoreoriginating after hangup.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-08-04
|
||||
|
||||
Currently, if an FXS channel is still off hook when
|
||||
all calls on the line have hung up, the user is provided
|
||||
reorder tone until going back on hook again.
|
||||
|
||||
In addition to not reflecting what most commercial switches
|
||||
actually do, it's very common for switches to automatically
|
||||
reoriginate for the user so that dial tone is provided without
|
||||
the user having to depress and release the hookswitch manually.
|
||||
This can increase convenience for users.
|
||||
|
||||
This behavior is now supported for kewlstart FXS channels.
|
||||
It's supported only for kewlstart (FXOKS) mainly because the
|
||||
behavior doesn't make any sense for ground start channels,
|
||||
and loop start signalling doesn't provide the necessary DAHDI
|
||||
event that makes this easy to implement. Likely almost everyone
|
||||
is using FXOKS over FXOLS anyways since FXOLS is pretty useless
|
||||
these days.
|
||||
|
||||
ASTERISK-30357 #close
|
||||
|
||||
Resolves: #224
|
||||
|
||||
UserNote: The autoreoriginate setting now allows for kewlstart FXS
|
||||
channels to automatically reoriginate and provide dial tone to the
|
||||
user again after all calls on the line have cleared. This saves users
|
||||
from having to manually hang up and pick up the receiver again before
|
||||
making another call.
|
||||
|
||||
|
||||
- ### audiohook: Unlock channel in mute if no audiohooks present.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-08-09
|
||||
|
||||
In the case where mute was called on a channel that had no
|
||||
audiohooks the code was not unlocking the channel, resulting
|
||||
in a deadlock.
|
||||
|
||||
Resolves: #233
|
||||
|
||||
- ### sig_analog: Allow three-way flash to time out to silence.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-07-10
|
||||
|
||||
sig_analog allows users to flash and use the three-way dial
|
||||
tone as a primitive hold function, simply by never timing
|
||||
it out.
|
||||
|
||||
Some systems allow this dial tone to time out to silence,
|
||||
so the user is not annoyed by a persistent dial tone.
|
||||
This option allows the dial tone to time out normally to
|
||||
silence.
|
||||
|
||||
ASTERISK-30004 #close
|
||||
Resolves: #205
|
||||
|
||||
UserNote: The threewaysilenthold option now allows the three-way
|
||||
dial tone to time out to silence, rather than continuing forever.
|
||||
|
||||
|
||||
- ### res_prometheus: Do not generate broken metrics
|
||||
Author: Holger Hans Peter Freyther
|
||||
Date: 2023-04-07
|
||||
|
||||
In 8d6fdf9c3adede201f0ef026dab201b3a37b26b6 invisible bridges were
|
||||
skipped but that lead to producing metrics with no name and no help.
|
||||
|
||||
Keep track of the number of metrics configured and then only emit these.
|
||||
Add a basic testcase that verifies that there is no '(NULL)' in the
|
||||
output.
|
||||
|
||||
ASTERISK-30474
|
||||
|
||||
|
||||
- ### res_pjsip: Enable TLS v1.3 if present.
|
||||
Author: Sean Bright
|
||||
Date: 2023-08-02
|
||||
|
||||
Fixes #221
|
||||
|
||||
UserNote: res_pjsip now allows TLS v1.3 to be enabled if supported by
|
||||
the underlying PJSIP library. The bundled version of PJSIP supports
|
||||
TLS v1.3.
|
||||
|
||||
|
||||
- ### func_cut: Add example to documentation.
|
||||
Author: phoneben
|
||||
Date: 2023-07-19
|
||||
|
||||
This adds an example to the XML documentation clarifying usage
|
||||
of the CUT function to address a common misusage.
|
||||
|
||||
|
||||
- ### extensions.conf.sample: Remove reference to missing context.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-16
|
||||
|
||||
c3ff4648 removed the [iaxtel700] context but neglected to remove
|
||||
references to it.
|
||||
|
||||
This commit addresses that and also removes iaxtel and freeworlddialup
|
||||
references from other config files.
|
||||
|
||||
|
||||
- ### func_export: Use correct function argument as variable name.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-12
|
||||
|
||||
Fixes #208
|
||||
|
||||
|
||||
- ### app_queue: Add support for applying caller priority change immediately.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2023-07-07
|
||||
|
||||
The app_queue module provides both an AMI action and a CLI command
|
||||
to change the priority of a caller in a queue. Up to now this change
|
||||
of priority has only been reflected to new callers into the queue.
|
||||
|
||||
This change adds an "immediate" option to both the AMI action and
|
||||
CLI command which immediately applies the priority change respective
|
||||
to the other callers already in the queue. This can allow, for example,
|
||||
a caller to be placed at the head of the queue immediately if their
|
||||
priority is sufficient.
|
||||
|
||||
Resolves: #202
|
||||
|
||||
UserNote: The 'queue priority caller' CLI command and
|
||||
'QueueChangePriorityCaller' AMI action now have an 'immediate'
|
||||
argument which allows the caller priority change to be reflected
|
||||
immediately, causing the position of a caller to move within the
|
||||
queue depending on the priorities of the other callers.
|
||||
|
||||
|
||||
- ### .github: Fix cherry-pick reminder issues
|
||||
Author: George Joseph
|
||||
Date: 2023-07-17
|
||||
|
||||
|
||||
- ### chan_iax2.c: Avoid crash with IAX2 switch support.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-07
|
||||
|
||||
A change made in 82cebaa0 did not properly handle the case when a
|
||||
channel was not provided, triggering a crash. ast_check_hangup(...)
|
||||
does not protect against NULL pointers.
|
||||
|
||||
Fixes #180
|
||||
|
||||
|
||||
- ### res_geolocation: Ensure required 'location_info' is present.
|
||||
Author: Sean Bright
|
||||
Date: 2023-07-07
|
||||
|
||||
Fixes #189
|
||||
|
||||
|
||||
- ### Adds manager actions to allow move/remove/forward individual messages in a particular mailbox folder. The forward command can be used to copy a message within a mailbox or to another mailbox. Also adds a VoicemailBoxSummarry, required to retrieve message ID's.
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-29
|
||||
|
||||
Resolves: #181
|
||||
|
||||
UserNote: The following manager actions have been added
|
||||
|
||||
VoicemailBoxSummary - Generate message list for a given mailbox
|
||||
|
||||
VoicemailRemove - Remove a message from a mailbox folder
|
||||
|
||||
VoicemailMove - Move a message from one folder to another within a mailbox
|
||||
|
||||
VoicemailForward - Copy a message from one folder in one mailbox
|
||||
to another folder in another or the same mailbox.
|
||||
|
||||
|
||||
- ### app_voicemail: add CLI commands for message manipulation
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-06-20
|
||||
|
||||
Adds CLI commands to allow move/remove/forward individual messages
|
||||
from a particular mailbox folder. The forward command can be used
|
||||
to copy a message within a mailbox or to another mailbox. Also adds
|
||||
a show mailbox, required to retrieve message ID's.
|
||||
|
||||
Resolves: #170
|
||||
|
||||
UserNote: The following CLI commands have been added to app_voicemail
|
||||
|
||||
voicemail show mailbox <mailbox> <context>
|
||||
Show contents of mailbox <mailbox>@<context>
|
||||
|
||||
voicemail remove <mailbox> <context> <from_folder> <messageid>
|
||||
Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>
|
||||
|
||||
voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>
|
||||
Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>
|
||||
|
||||
voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>
|
||||
Forward message <messageid> in mailbox <mailbox>@<context> <from_folder> to
|
||||
mailbox <mailbox>@<context> <to_folder>
|
||||
|
||||
|
||||
- ### res_rtp_asterisk: Move ast_rtp_rtcp_report_alloc using `rtp->themssrc_valid` into the scope of the rtp_instance lock.
|
||||
Author: zhengsh
|
||||
Date: 2023-06-30
|
||||
|
||||
From the gdb information, it was found that when calling __ast_free, the size of the
|
||||
allocated space pointed to by the pointer matches the size created when rtp->themssrc_valid
|
||||
is equal to 0. However, in reality, when reading the value of rtp->themssrc_valid in gdb,
|
||||
it is found to be 1.
|
||||
|
||||
Within ast_rtcp_write(), the call to ast_rtp_rtcp_report_alloc() uses rtp->themssrc_valid,
|
||||
which is outside the protection of the rtp_instance lock. However,
|
||||
ast_rtcp_generate_report(), which is called by ast_rtcp_generate_compound_prefix(), uses
|
||||
rtp->themssrc_valid within the protection of the rtp_instance lock.
|
||||
|
||||
This can lead to the possibility that the value of rtp->themssrc_valid used in the call to
|
||||
ast_rtp_rtcp_report_alloc() may be different from the value of rtp->themssrc_valid used
|
||||
within ast_rtcp_generate_report().
|
||||
|
||||
Resolves: asterisk#63
|
||||
|
||||
- ### .github: Minor tweak to Asterisk Releaser
|
||||
Author: George Joseph
|
||||
Date: 2023-07-12
|
||||
|
||||
|
||||
- ### .github: Suppress cherry-pick reminder for some situations
|
||||
Author: George Joseph
|
||||
Date: 2023-07-11
|
||||
|
||||
In PROpenedOrUpdated, the cherry-pick reminder will now be
|
||||
suppressed if there are already valid 'cherry-pick-to' comments
|
||||
in the PR or the PR contained a 'cherry-pick-to: none' comment.
|
||||
|
||||
|
||||
- ### sig_analog: Allow immediate fake ring to be suppressed.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-06-08
|
||||
|
||||
When immediate=yes on an FXS channel, sig_analog will
|
||||
start fake audible ringback that continues until the
|
||||
channel is answered. Even if it answers immediately,
|
||||
the ringback is still audible for a brief moment.
|
||||
This can be disruptive and unwanted behavior.
|
||||
|
||||
This adds an option to disable this behavior, though
|
||||
the default behavior remains unchanged.
|
||||
|
||||
ASTERISK-30003 #close
|
||||
Resolves: #118
|
||||
|
||||
UserNote: The immediatering option can now be set to no to suppress
|
||||
the fake audible ringback provided when immediate=yes on FXS channels.
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.1
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.1.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.5.0...20.5.1)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.1.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
- res_pjsip: disable raw bad packet logging
|
||||
- res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
- manager.c: Prevent path traversal with GetConfig.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
None
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Ben Ford (1):
|
||||
- manager.c: Prevent path traversal with GetConfig.
|
||||
|
||||
- ### George Joseph (1):
|
||||
- res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
|
||||
- ### Gitea (1):
|
||||
- res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
|
||||
- ### Mike Bradeen (1):
|
||||
- res_pjsip: disable raw bad packet logging
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_pjsip_header_funcs: Duplicate new header value, don't copy.
|
||||
Author: Gitea
|
||||
Date: 2023-07-10
|
||||
|
||||
When updating an existing header the 'update' code incorrectly
|
||||
just copied the new value into the existing buffer. If the
|
||||
new value exceeded the available buffer size memory outside
|
||||
of the buffer would be written into, potentially causing
|
||||
a crash.
|
||||
|
||||
This change makes it so that the 'update' now duplicates
|
||||
the new header value instead of copying it into the existing
|
||||
buffer.
|
||||
|
||||
- ### res_pjsip: disable raw bad packet logging
|
||||
Author: Mike Bradeen
|
||||
Date: 2023-07-25
|
||||
|
||||
Add patch to split the log level for invalid packets received on the
|
||||
signaling port. The warning regarding the packet will move to level 2
|
||||
so that it can still be displayed, while the raw packet will be at level
|
||||
4.
|
||||
|
||||
- ### res_rtp_asterisk.c: Check DTLS packets against ICE candidate list
|
||||
Author: George Joseph
|
||||
Date: 2023-11-09
|
||||
|
||||
When ICE is in use, we can prevent a possible DOS attack by allowing
|
||||
DTLS protocol messages (client hello, etc) only from sources that
|
||||
are in the active remote candidates list.
|
||||
|
||||
Resolves: GHSA-hxj9-xwr8-w8pq
|
||||
|
||||
- ### manager.c: Prevent path traversal with GetConfig.
|
||||
Author: Ben Ford
|
||||
Date: 2023-11-13
|
||||
|
||||
When using AMI GetConfig, it was possible to access files outside of the
|
||||
Asterisk configuration directory by using filenames with ".." and "./"
|
||||
even while live_dangerously was not enabled. This change resolves the
|
||||
full path and ensures we are still in the configuration directory before
|
||||
attempting to access the file.
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
Change Log for Release asterisk-20.5.2
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.5.2.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.5.1...20.5.2)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.5.2.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #500: [bug regression]: res_rtp_asterisk doesn't build if pjproject isn't used
|
||||
- #503: [bug]: The res_rtp_asterisk DTLS check against ICE candidates fails when it shouldn't
|
||||
- #505: [bug]: res_pjproject: ast_sockaddr_cmp() always fails on sockaddrs created by ast_sockaddr_from_pj_sockaddr()
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### George Joseph (1):
|
||||
- res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_rtp_asterisk: Fix regression issues with DTLS client check
|
||||
Author: George Joseph
|
||||
Date: 2023-12-15
|
||||
|
||||
* Since ICE candidates are used for the check and pjproject is
|
||||
required to use ICE, res_rtp_asterisk was failing to compile
|
||||
when pjproject wasn't available. The check is now wrapped
|
||||
with an #ifdef HAVE_PJPROJECT.
|
||||
|
||||
* The rtp->ice_active_remote_candidates container was being
|
||||
used to check the address on incoming packets but that
|
||||
container doesn't contain peer reflexive candidates discovered
|
||||
during negotiation. This was causing the check to fail
|
||||
where it shouldn't. We now check against pjproject's
|
||||
real_ice->rcand array which will contain those candidates.
|
||||
|
||||
* Also fixed a bug in ast_sockaddr_from_pj_sockaddr() where
|
||||
we weren't zeroing out sin->sin_zero before returning. This
|
||||
was causing ast_sockaddr_cmp() to always return false when
|
||||
one of the inputs was converted from a pj_sockaddr, even
|
||||
if both inputs had the same address and port.
|
||||
|
||||
Resolves: #500
|
||||
Resolves: #503
|
||||
Resolves: #505
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,736 @@
|
|||
|
||||
Change Log for Release asterisk-20.7.0
|
||||
========================================
|
||||
|
||||
Links:
|
||||
----------------------------------------
|
||||
|
||||
- [Full ChangeLog](https://downloads.asterisk.org/pub/telephony/asterisk/releases/ChangeLog-20.7.0.md)
|
||||
- [GitHub Diff](https://github.com/asterisk/asterisk/compare/20.6.0...20.7.0)
|
||||
- [Tarball](https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-20.7.0.tar.gz)
|
||||
- [Downloads](https://downloads.asterisk.org/pub/telephony/asterisk)
|
||||
|
||||
Summary:
|
||||
----------------------------------------
|
||||
|
||||
- res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
- app_dial: Add dial time for progress/ringing.
|
||||
- app_voicemail: Properly reinitialize config after unit tests.
|
||||
- app_queue.c : fix "queue add member" usage string
|
||||
- app_voicemail: Allow preventing mark messages as urgent.
|
||||
- res_pjsip: Use consistent type for boolean columns.
|
||||
- attestation_config.c: Use ast_free instead of ast_std_free
|
||||
- Makefile: Add stir_shaken/cache to directories created on install
|
||||
- Stir/Shaken Refactor
|
||||
- alembic: Synchronize alembic heads between supported branches.
|
||||
- translate.c: implement new direct comp table mode
|
||||
- README.md: Removed outdated link
|
||||
- strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
- res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
- dsp.c: Fix and improve potentially inaccurate log message.
|
||||
- pjsip show channelstats: Prevent possible segfault when faxing
|
||||
- Reduce startup/shutdown verbose logging
|
||||
- configure: Rerun bootstrap on modern platform.
|
||||
- Upgrade bundled pjproject to 2.14.
|
||||
- app_speech_utils.c: Allow partial speech results.
|
||||
- utils: Make behavior of ast_strsep* match strsep.
|
||||
- app_chanspy: Add 'D' option for dual-channel audio
|
||||
- app_if: Fix next priority calculation.
|
||||
- res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
- BuildSystem: Bump autotools versions on OpenBSD.
|
||||
- main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
- res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
- rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
- manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
- res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
- app_confbridge: Don't emit warnings on valid configurations.
|
||||
- app_voicemail: add NoOp alembic script to maintain sync
|
||||
- chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
- chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
- chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
- func_frame_trace: Add CLI command to dump frame queue.
|
||||
|
||||
User Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### app_dial: Add dial time for progress/ringing.
|
||||
The timeout argument to Dial now allows
|
||||
specifying the maximum amount of time to dial if
|
||||
early media is not received.
|
||||
|
||||
- ### app_voicemail: Allow preventing mark messages as urgent.
|
||||
The leaveurgent mailbox option can now be used to
|
||||
control whether callers may leave messages marked as 'Urgent'.
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
Asterisk's stir-shaken feature has been refactored to
|
||||
correct interoperability, RFC compliance, and performance issues.
|
||||
See https://docs.asterisk.org/Deployment/STIR-SHAKEN for more
|
||||
information.
|
||||
|
||||
- ### Upgrade bundled pjproject to 2.14.
|
||||
Bundled pjproject has been upgraded to 2.14. For more
|
||||
information on what all is included in this change, check out the
|
||||
pjproject Github page: https://github.com/pjsip/pjproject/releases
|
||||
|
||||
- ### app_speech_utils.c: Allow partial speech results.
|
||||
The SpeechBackground dialplan application now supports a 'p'
|
||||
option that will return partial results from speech engines that
|
||||
provide them when a timeout occurs.
|
||||
|
||||
- ### app_chanspy: Add 'D' option for dual-channel audio
|
||||
The ChanSpy application now accepts the 'D' option which
|
||||
will interleave the spied audio within the outgoing frames. The
|
||||
purpose of this is to allow the audio to be read as a Dual channel
|
||||
stream with separate incoming and outgoing audio. Setting both the
|
||||
'o' option and the 'D' option and results in the 'D' option being
|
||||
ignored.
|
||||
|
||||
- ### chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
The 'dahdi set mwi' now allows MWI on channels
|
||||
to be manually toggled if needed for troubleshooting.
|
||||
Resolves: #440
|
||||
|
||||
|
||||
Upgrade Notes:
|
||||
----------------------------------------
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
The stir-shaken refactor is a breaking change but since
|
||||
it's not working now we don't think it matters. The
|
||||
stir_shaken.conf file has changed significantly which means that
|
||||
existing ones WILL need to be changed. The stir_shaken.conf.sample
|
||||
file in configs/samples/ has quite a bit more information. This is
|
||||
also an ABI breaking change since some of the existing objects
|
||||
needed to be changed or removed, and new ones added. Additionally,
|
||||
if res_stir_shaken is enabled in menuselect, you'll need to either
|
||||
have the development package for libjwt v1.15.3 installed or use
|
||||
the --with-libjwt-bundled option with ./configure.
|
||||
|
||||
|
||||
Closed Issues:
|
||||
----------------------------------------
|
||||
|
||||
- #46: [bug]: Stir/Shaken: Wrong CID used when looking up certificates
|
||||
- #351: [improvement]: Refactor res_stir_shaken to use libjwt
|
||||
- #406: [improvement]: pjsip: Upgrade bundled version to pjproject 2.14
|
||||
- #440: [new-feature]: chan_dahdi: Allow manually toggling MWI on channels
|
||||
- #492: [improvement]: res_calendar_icalendar: Print icalendar error if available on parsing failure
|
||||
- #527: [bug]: app_voicemail_odbc no longer working after removal of macrocontext.
|
||||
- #529: [bug]: MulticastRTP without selected codec leeds to "FRACK!, Failed assertion bad magic number 0x0 for object" after ~30 calls
|
||||
- #533: [improvement]: channel.c, func_frame_trace.c: Improve debuggability of channel frame queue
|
||||
- #551: [bug]: manager: UpdateConfig triggers reload with "Reload: no"
|
||||
- #560: [bug]: EndIf() causes next priority to be skipped
|
||||
- #565: [bug]: Application Read() returns immediately
|
||||
- #569: [improvement]: Add option to interleave input and output frames on spied channel
|
||||
- #572: [improvement]: Copy partial speech results when Asterisk is ready to move on but the speech backend is not
|
||||
- #582: [improvement]: Reduce unneeded logging during startup and shutdown
|
||||
- #586: [bug]: The "restrict" keyword used in chan_iax2.c isn't supported in older gcc versions
|
||||
- #588: [new-feature]: app_dial: Allow Dial to be aborted if early media is not received
|
||||
- #592: [bug]: In certain circumstances, "pjsip show channelstats" can segfault when a fax session is active
|
||||
- #595: [improvement]: dsp.c: Fix and improve confusing warning message.
|
||||
- #597: [bug]: wrong MOS calculation
|
||||
- #601: [new-feature]: translate.c: implement new direct comp table mode (PR #585)
|
||||
- #619: [new-feature]: app_voicemail: Allow preventing callers from marking messages as urgent
|
||||
- #629: [bug]: app_voicemail: Multiple executions of unit tests cause segfault
|
||||
- #634: [bug]: make install doesn't create the stir_shaken cache directory
|
||||
- #636: [bug]: Possible SEGV in res_stir_shaken due to wrong free function
|
||||
- #645: [bug]: Occasional SEGV in res_pjsip_stir_shaken.c
|
||||
|
||||
Commits By Author:
|
||||
----------------------------------------
|
||||
|
||||
- ### Ben Ford (1):
|
||||
- Upgrade bundled pjproject to 2.14.
|
||||
|
||||
- ### Brad Smith (2):
|
||||
- main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
- BuildSystem: Bump autotools versions on OpenBSD.
|
||||
|
||||
- ### George Joseph (6):
|
||||
- Reduce startup/shutdown verbose logging
|
||||
- pjsip show channelstats: Prevent possible segfault when faxing
|
||||
- Stir/Shaken Refactor
|
||||
- Makefile: Add stir_shaken/cache to directories created on install
|
||||
- attestation_config.c: Use ast_free instead of ast_std_free
|
||||
- res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
|
||||
- ### Joshua C. Colp (1):
|
||||
- utils: Make behavior of ast_strsep* match strsep.
|
||||
|
||||
- ### Mike Bradeen (2):
|
||||
- app_voicemail: add NoOp alembic script to maintain sync
|
||||
- app_chanspy: Add 'D' option for dual-channel audio
|
||||
|
||||
- ### Naveen Albert (10):
|
||||
- func_frame_trace: Add CLI command to dump frame queue.
|
||||
- chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
- res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
- manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
- app_if: Fix next priority calculation.
|
||||
- configure: Rerun bootstrap on modern platform.
|
||||
- dsp.c: Fix and improve potentially inaccurate log message.
|
||||
- app_voicemail: Allow preventing mark messages as urgent.
|
||||
- app_voicemail: Properly reinitialize config after unit tests.
|
||||
- app_dial: Add dial time for progress/ringing.
|
||||
|
||||
- ### PeterHolik (2):
|
||||
- chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
- chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
|
||||
- ### Sean Bright (7):
|
||||
- app_confbridge: Don't emit warnings on valid configurations.
|
||||
- rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
- res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
- res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
- strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
- alembic: Synchronize alembic heads between supported branches.
|
||||
- res_pjsip: Use consistent type for boolean columns.
|
||||
|
||||
- ### Sebastian Jennen (1):
|
||||
- translate.c: implement new direct comp table mode
|
||||
|
||||
- ### Shaaah (1):
|
||||
- app_queue.c : fix "queue add member" usage string
|
||||
|
||||
- ### Shyju Kanaprath (1):
|
||||
- README.md: Removed outdated link
|
||||
|
||||
- ### cmaj (1):
|
||||
- app_speech_utils.c: Allow partial speech results.
|
||||
|
||||
- ### romryz (1):
|
||||
- res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
|
||||
|
||||
Detail:
|
||||
----------------------------------------
|
||||
|
||||
- ### res_pjsip_stir_shaken.c: Add checks for missing parameters
|
||||
Author: George Joseph
|
||||
Date: 2024-03-11
|
||||
|
||||
* Added checks for missing session, session->channel and rdata
|
||||
in stir_shaken_incoming_request.
|
||||
|
||||
* Added checks for missing session, session->channel and tdata
|
||||
in stir_shaken_outgoing_request.
|
||||
|
||||
Resolves: #645
|
||||
|
||||
- ### app_dial: Add dial time for progress/ringing.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-08
|
||||
|
||||
Add a timeout option to control the amount of time
|
||||
to wait if no early media is received before giving
|
||||
up. This allows aborting early if the destination
|
||||
is not being responsive.
|
||||
|
||||
Resolves: #588
|
||||
|
||||
UserNote: The timeout argument to Dial now allows
|
||||
specifying the maximum amount of time to dial if
|
||||
early media is not received.
|
||||
|
||||
|
||||
- ### app_voicemail: Properly reinitialize config after unit tests.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-29
|
||||
|
||||
Most app_voicemail unit tests were not properly cleaning up
|
||||
after themselves after running. This led to test mailboxes
|
||||
lingering around in the system. It also meant that if any
|
||||
unit tests in app_voicemail that create mailboxes were executed
|
||||
and the module was not unloaded/loaded again prior to running
|
||||
the test_voicemail_vm_info unit test, Asterisk would segfault
|
||||
due to an attempt to copy a NULL string.
|
||||
|
||||
The load_config test did actually have logic to reinitialize
|
||||
the config after the test. However, this did not work in practice
|
||||
since load_config() would not reload the config since voicemail.conf
|
||||
had not changed during the test; thus, additional logic has been
|
||||
added to ensure that voicemail.conf is truly reloaded, after any
|
||||
unit tests which modify the users list.
|
||||
|
||||
This prevents the SEGV due to invalid mailboxes lingering around,
|
||||
and also ensures that the system state is restored to what it was
|
||||
prior to the tests running.
|
||||
|
||||
Resolves: #629
|
||||
|
||||
- ### app_queue.c : fix "queue add member" usage string
|
||||
Author: Shaaah
|
||||
Date: 2024-01-23
|
||||
|
||||
Fixing bracket placement in the "queue add member" cli usage string.
|
||||
|
||||
|
||||
- ### app_voicemail: Allow preventing mark messages as urgent.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-24
|
||||
|
||||
This adds an option to allow preventing callers from leaving
|
||||
messages marked as 'urgent'.
|
||||
|
||||
Resolves: #619
|
||||
|
||||
UserNote: The leaveurgent mailbox option can now be used to
|
||||
control whether callers may leave messages marked as 'Urgent'.
|
||||
|
||||
|
||||
- ### res_pjsip: Use consistent type for boolean columns.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-27
|
||||
|
||||
This migrates the relevant schema objects from the `('yes', 'no')`
|
||||
definition to the `('0', '1', 'off', 'on', 'false', 'true', 'yes', 'no')`
|
||||
one.
|
||||
|
||||
Fixes #617
|
||||
|
||||
|
||||
- ### attestation_config.c: Use ast_free instead of ast_std_free
|
||||
Author: George Joseph
|
||||
Date: 2024-03-05
|
||||
|
||||
In as_check_common_config, we were calling ast_std_free on
|
||||
raw_key but raw_key was allocated with ast_malloc so it
|
||||
should be freed with ast_free.
|
||||
|
||||
Resolves: #636
|
||||
|
||||
- ### Makefile: Add stir_shaken/cache to directories created on install
|
||||
Author: George Joseph
|
||||
Date: 2024-03-04
|
||||
|
||||
The default location for the stir_shaken cache is
|
||||
/var/lib/asterisk/keys/stir_shaken/cache but we were only creating
|
||||
/var/lib/asterisk/keys/stir_shaken on istall. We now create
|
||||
the cache sub-directory.
|
||||
|
||||
Resolves: #634
|
||||
|
||||
- ### Stir/Shaken Refactor
|
||||
Author: George Joseph
|
||||
Date: 2023-10-26
|
||||
|
||||
Why do we need a refactor?
|
||||
|
||||
The original stir/shaken implementation was started over 3 years ago
|
||||
when little was understood about practical implementation. The
|
||||
result was an implementation that wouldn't actually interoperate
|
||||
with any other stir-shaken implementations.
|
||||
|
||||
There were also a number of stir-shaken features and RFC
|
||||
requirements that were never implemented such as TNAuthList
|
||||
certificate validation, sending Reason headers in SIP responses
|
||||
when verification failed but we wished to continue the call, and
|
||||
the ability to send Media Key(mky) grants in the Identity header
|
||||
when the call involved DTLS.
|
||||
|
||||
Finally, there were some performance concerns around outgoing
|
||||
calls and selection of the correct certificate and private key.
|
||||
The configuration was keyed by an arbitrary name which meant that
|
||||
for every outgoing call, we had to scan the entire list of
|
||||
configured TNs to find the correct cert to use. With only a few
|
||||
TNs configured, this wasn't an issue but if you have a thousand,
|
||||
it could be.
|
||||
|
||||
What's changed?
|
||||
|
||||
* Configuration objects have been refactored to be clearer about
|
||||
their uses and to fix issues.
|
||||
* The "general" object was renamed to "verification" since it
|
||||
contains parameters specific to the incoming verification
|
||||
process. It also never handled ca_path and crl_path
|
||||
correctly.
|
||||
* A new "attestation" object was added that controls the
|
||||
outgoing attestation process. It sets default certificates,
|
||||
keys, etc.
|
||||
* The "certificate" object was renamed to "tn" and had it's key
|
||||
change to telephone number since outgoing call attestation
|
||||
needs to look up certificates by telephone number.
|
||||
* The "profile" object had more parameters added to it that can
|
||||
override default parameters specified in the "attestation"
|
||||
and "verification" objects.
|
||||
* The "store" object was removed altogther as it was never
|
||||
implemented.
|
||||
|
||||
* We now use libjwt to create outgoing Identity headers and to
|
||||
parse and validate signatures on incoming Identiy headers. Our
|
||||
previous custom implementation was much of the source of the
|
||||
interoperability issues.
|
||||
|
||||
* General code cleanup and refactor.
|
||||
* Moved things to better places.
|
||||
* Separated some of the complex functions to smaller ones.
|
||||
* Using context objects rather than passing tons of parameters
|
||||
in function calls.
|
||||
* Removed some complexity and unneeded encapsuation from the
|
||||
config objects.
|
||||
|
||||
Resolves: #351
|
||||
Resolves: #46
|
||||
|
||||
UserNote: Asterisk's stir-shaken feature has been refactored to
|
||||
correct interoperability, RFC compliance, and performance issues.
|
||||
See https://docs.asterisk.org/Deployment/STIR-SHAKEN for more
|
||||
information.
|
||||
|
||||
UpgradeNote: The stir-shaken refactor is a breaking change but since
|
||||
it's not working now we don't think it matters. The
|
||||
stir_shaken.conf file has changed significantly which means that
|
||||
existing ones WILL need to be changed. The stir_shaken.conf.sample
|
||||
file in configs/samples/ has quite a bit more information. This is
|
||||
also an ABI breaking change since some of the existing objects
|
||||
needed to be changed or removed, and new ones added. Additionally,
|
||||
if res_stir_shaken is enabled in menuselect, you'll need to either
|
||||
have the development package for libjwt v1.15.3 installed or use
|
||||
the --with-libjwt-bundled option with ./configure.
|
||||
|
||||
|
||||
- ### alembic: Synchronize alembic heads between supported branches.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-28
|
||||
|
||||
This adds a dummy migration to 18 and 20 so that our alembic heads are
|
||||
synchronized across all supported branches.
|
||||
|
||||
In this case the migration we are stubbing (24c12d8e9014) is:
|
||||
|
||||
https://github.com/asterisk/asterisk/commit/775352ee6c2a5bcd4f0e3df51aee5d1b0abf4cbe
|
||||
|
||||
- ### translate.c: implement new direct comp table mode
|
||||
Author: Sebastian Jennen
|
||||
Date: 2024-02-25
|
||||
|
||||
The new mode lists for each codec translation the actual real cost in cpu microseconds per second translated audio.
|
||||
This allows to compare the real cpu usage of translations and helps in evaluation of codec implementation changes regarding performance (regression testing).
|
||||
|
||||
- add new table mode
|
||||
- hide the 999999 comp values, as these only indicate an issue with transcoding
|
||||
- hide the 0 values, as these also do not contain any information (only indicate a multistep transcoding)
|
||||
|
||||
Resolves: #601
|
||||
|
||||
- ### README.md: Removed outdated link
|
||||
Author: Shyju Kanaprath
|
||||
Date: 2024-02-23
|
||||
|
||||
Removed outdated link http://www.quicknet.net from README.md
|
||||
|
||||
cherry-pick-to: 18
|
||||
cherry-pick-to: 20
|
||||
cherry-pick-to: 21
|
||||
|
||||
- ### strings.h: Ensure ast_str_buffer(…) returns a 0 terminated string.
|
||||
Author: Sean Bright
|
||||
Date: 2024-02-17
|
||||
|
||||
If a dynamic string is created with an initial length of 0,
|
||||
`ast_str_buffer(…)` will return an invalid pointer.
|
||||
|
||||
This was a secondary discovery when fixing #65.
|
||||
|
||||
|
||||
- ### res_rtp_asterisk.c: Correct coefficient in MOS calculation.
|
||||
Author: romryz
|
||||
Date: 2024-02-06
|
||||
|
||||
Media Experience Score relies on incorrect pseudo_mos variable
|
||||
calculation. According to forming an opinion section of the
|
||||
documentation, calculation relies on ITU-T G.107 standard:
|
||||
|
||||
https://docs.asterisk.org/Deployment/Media-Experience-Score/#forming-an-opinion
|
||||
|
||||
ITU-T G.107 Annex B suggests to calculate MOS with a coefficient
|
||||
"seven times ten to the power of negative six", 7 * 10^(-6). which
|
||||
would mean 6 digits after the decimal point. Current implementation
|
||||
has 7 digits after the decimal point, which downrates the calls.
|
||||
|
||||
Fixes: #597
|
||||
|
||||
- ### dsp.c: Fix and improve potentially inaccurate log message.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-09
|
||||
|
||||
If ast_dsp_process is called with a codec besides slin, ulaw,
|
||||
or alaw, a warning is logged that in-band DTMF is not supported,
|
||||
but this message is not always appropriate or correct, because
|
||||
ast_dsp_process is much more generic than just DTMF detection.
|
||||
|
||||
This logs a more generic message in those cases, and also improves
|
||||
codec-mismatch logging throughout dsp.c by ensuring incompatible
|
||||
codecs are printed out.
|
||||
|
||||
Resolves: #595
|
||||
|
||||
- ### pjsip show channelstats: Prevent possible segfault when faxing
|
||||
Author: George Joseph
|
||||
Date: 2024-02-09
|
||||
|
||||
Under rare circumstances, it's possible for the original audio
|
||||
session in the active_media_state default_session to be corrupted
|
||||
instead of removed when switching to the t38/image media session
|
||||
during fax negotiation. This can cause a segfault when a "pjsip
|
||||
show channelstats" attempts to print that audio media session's
|
||||
rtp statistics. In these cases, the active_media_state
|
||||
topology is correctly showing only a single t38/image stream
|
||||
so we now check that there's an audio stream in the topology
|
||||
before attempting to use the audio media session to get the rtp
|
||||
statistics.
|
||||
|
||||
Resolves: #592
|
||||
|
||||
- ### Reduce startup/shutdown verbose logging
|
||||
Author: George Joseph
|
||||
Date: 2024-01-31
|
||||
|
||||
When started with a verbose level of 3, asterisk can emit over 1500
|
||||
verbose message that serve no real purpose other than to fill up
|
||||
logs. When asterisk shuts down, it emits another 1100 that are of
|
||||
even less use. Since the testsuite runs asterisk with a verbose
|
||||
level of 3, and asterisk starts and stops for every one of the 700+
|
||||
tests, the number of log messages is staggering. Besides taking up
|
||||
resources, it also makes it hard to debug failing tests.
|
||||
|
||||
This commit changes the log level for those verbose messages to 5
|
||||
instead of 3 which reduces the number of log messages to only a
|
||||
handful. Of course, NOTICE, WARNING and ERROR message are
|
||||
unaffected.
|
||||
|
||||
There's also one other minor change...
|
||||
ast_context_remove_extension_callerid2() logs a DEBUG message
|
||||
instead of an ERROR if the extension you're deleting doesn't exist.
|
||||
The pjsip_config_wizard calls that function to clean up the config
|
||||
and has been triggering that annoying error message for years.
|
||||
|
||||
Resolves: #582
|
||||
|
||||
- ### configure: Rerun bootstrap on modern platform.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-02-12
|
||||
|
||||
The last time configure was run, it was run on a system that
|
||||
did not enable -std=gnu11 by default, which meant that the
|
||||
restrict qualifier would not be recognized on certain platforms.
|
||||
This regenerates the configure files from running bootstrap.sh,
|
||||
so that these should be recognized on all supported platforms.
|
||||
|
||||
Resolves: #586
|
||||
|
||||
- ### Upgrade bundled pjproject to 2.14.
|
||||
Author: Ben Ford
|
||||
Date: 2024-02-05
|
||||
|
||||
Fixes: #406
|
||||
|
||||
UserNote: Bundled pjproject has been upgraded to 2.14. For more
|
||||
information on what all is included in this change, check out the
|
||||
pjproject Github page: https://github.com/pjsip/pjproject/releases
|
||||
|
||||
|
||||
- ### app_speech_utils.c: Allow partial speech results.
|
||||
Author: cmaj
|
||||
Date: 2024-02-02
|
||||
|
||||
Adds 'p' option to SpeechBackground() application.
|
||||
With this option, when the app timeout is reached,
|
||||
whatever the backend speech engine collected will
|
||||
be returned as if it were the final, full result.
|
||||
(This works for engines that make partial results.)
|
||||
|
||||
Resolves: #572
|
||||
|
||||
UserNote: The SpeechBackground dialplan application now supports a 'p'
|
||||
option that will return partial results from speech engines that
|
||||
provide them when a timeout occurs.
|
||||
|
||||
|
||||
- ### utils: Make behavior of ast_strsep* match strsep.
|
||||
Author: Joshua C. Colp
|
||||
Date: 2024-01-31
|
||||
|
||||
Given the scenario of passing an empty string to the
|
||||
ast_strsep functions the functions would return NULL
|
||||
instead of an empty string. This is counter to how
|
||||
strsep itself works.
|
||||
|
||||
This change alters the behavior of the functions to
|
||||
match that of strsep.
|
||||
|
||||
Fixes: #565
|
||||
|
||||
- ### app_chanspy: Add 'D' option for dual-channel audio
|
||||
Author: Mike Bradeen
|
||||
Date: 2024-01-31
|
||||
|
||||
Adds the 'D' option to app chanspy that causes the input and output
|
||||
frames of the spied channel to be interleaved in the spy output frame.
|
||||
This allows the input and output of the spied channel to be decoded
|
||||
separately by the receiver.
|
||||
|
||||
If the 'o' option is also set, the 'D' option is ignored as the
|
||||
audio being spied is inherently one direction.
|
||||
|
||||
Fixes: #569
|
||||
|
||||
UserNote: The ChanSpy application now accepts the 'D' option which
|
||||
will interleave the spied audio within the outgoing frames. The
|
||||
purpose of this is to allow the audio to be read as a Dual channel
|
||||
stream with separate incoming and outgoing audio. Setting both the
|
||||
'o' option and the 'D' option and results in the 'D' option being
|
||||
ignored.
|
||||
|
||||
|
||||
- ### app_if: Fix next priority calculation.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-28
|
||||
|
||||
Commit fa3922a4d28860d415614347d9f06c233d2beb07 fixed
|
||||
a branching issue but "overshoots" when calculating
|
||||
the next priority. This fixes that; accompanying
|
||||
test suite tests have also been extended.
|
||||
|
||||
Resolves: #560
|
||||
|
||||
- ### res_pjsip_t38.c: Permit IPv6 SDP connection addresses.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-29
|
||||
|
||||
The existing code prevented IPv6 addresses from being properly parsed.
|
||||
|
||||
Fixes #558
|
||||
|
||||
|
||||
- ### BuildSystem: Bump autotools versions on OpenBSD.
|
||||
Author: Brad Smith
|
||||
Date: 2024-01-27
|
||||
|
||||
Bump up to the more commonly used and modern versions of
|
||||
autoconf and automake.
|
||||
|
||||
|
||||
- ### main/utils: Simplify the FreeBSD ast_get_tid() handling
|
||||
Author: Brad Smith
|
||||
Date: 2024-01-27
|
||||
|
||||
FreeBSD has had kernel threads for 20+ years.
|
||||
|
||||
|
||||
- ### res_pjsip_session.c: Correctly format SDP connection addresses.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-27
|
||||
|
||||
Resolves a regression identified by @justinludwig involving the
|
||||
rendering of IPv6 addresses in outgoing SDP.
|
||||
|
||||
Also updates `media_address` on PJSIP endpoints so that if we are able
|
||||
to parse the configured value as an IP we store it in a format that we
|
||||
can directly use later. Based on my reading of the code it appeared
|
||||
that one could configure `media_address` as:
|
||||
|
||||
```
|
||||
[foo]
|
||||
type = endpoint
|
||||
...
|
||||
media_address = [2001:db8::]
|
||||
```
|
||||
|
||||
And that value would be blindly copied into the outgoing SDP without
|
||||
regard to its format.
|
||||
|
||||
Fixes #541
|
||||
|
||||
|
||||
- ### rtp_engine.c: Correct sample rate typo for L16/44100.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-28
|
||||
|
||||
Fixes #555
|
||||
|
||||
|
||||
- ### manager.c: Fix erroneous reloads in UpdateConfig.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-25
|
||||
|
||||
Currently, a reload will always occur if the
|
||||
Reload header is provided for the UpdateConfig
|
||||
action. However, we should not be doing a reload
|
||||
if the header value has a falsy value, per the
|
||||
documentation, so this makes the reload behavior
|
||||
consistent with the existing documentation.
|
||||
|
||||
Resolves: #551
|
||||
|
||||
- ### res_calendar_icalendar: Print iCalendar error on parsing failure.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-12-14
|
||||
|
||||
If libical fails to parse a calendar, print the error message it provdes.
|
||||
|
||||
Resolves: #492
|
||||
|
||||
- ### app_confbridge: Don't emit warnings on valid configurations.
|
||||
Author: Sean Bright
|
||||
Date: 2024-01-21
|
||||
|
||||
The numeric bridge profile options `internal_sample_rate` and
|
||||
`maximum_sample_rate` are documented to accept the special values
|
||||
`auto` and `none`, respectively. While these values currently work,
|
||||
they also emit warnings when used which could be confusing for users.
|
||||
|
||||
In passing, also ensure that we only accept the documented range of
|
||||
sample rate values between 8000 and 192000.
|
||||
|
||||
Fixes #546
|
||||
|
||||
|
||||
- ### app_voicemail: add NoOp alembic script to maintain sync
|
||||
Author: Mike Bradeen
|
||||
Date: 2024-01-17
|
||||
|
||||
Adding a NoOp alembic script for the voicemail database to maintain
|
||||
version sync with other branches.
|
||||
|
||||
Fixes: #527
|
||||
|
||||
- ### chan_dahdi: Allow MWI to be manually toggled on channels.
|
||||
Author: Naveen Albert
|
||||
Date: 2023-11-10
|
||||
|
||||
This adds a CLI command to manually toggle the MWI status
|
||||
of a channel, useful for troubleshooting or resetting
|
||||
MWI devices, similar to the capabilities offered with
|
||||
SIP messaging to manually control MWI status.
|
||||
|
||||
UserNote: The 'dahdi set mwi' now allows MWI on channels
|
||||
to be manually toggled if needed for troubleshooting.
|
||||
|
||||
Resolves: #440
|
||||
|
||||
- ### chan_rtp.c: MulticastRTP missing refcount without codec option
|
||||
Author: PeterHolik
|
||||
Date: 2024-01-15
|
||||
|
||||
Fixes: #529
|
||||
|
||||
- ### chan_rtp.c: Change MulticastRTP nameing to avoid memory leak
|
||||
Author: PeterHolik
|
||||
Date: 2024-01-16
|
||||
|
||||
Fixes: asterisk#536
|
||||
|
||||
- ### func_frame_trace: Add CLI command to dump frame queue.
|
||||
Author: Naveen Albert
|
||||
Date: 2024-01-12
|
||||
|
||||
This adds a simple CLI command that can be used for
|
||||
analyzing all frames currently queued to a channel.
|
||||
|
||||
A couple log messages are also adjusted to be more
|
||||
useful in tracing bridging problems.
|
||||
|
||||
Resolves: #533
|
||||
|
|
@ -12,10 +12,316 @@
|
|||
===
|
||||
==============================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 20.1.0 to Asterisk 20.2.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
app_broadcast
|
||||
------------------
|
||||
* A Broadcast application is now available which allows
|
||||
for asynchronous one-to-many and many-to-one channel audio.
|
||||
|
||||
app_directory
|
||||
------------------
|
||||
* A new option 's' has been added to the Directory() application that
|
||||
will skip calling the extension and instead set the extension as
|
||||
DIRECTORY_EXTEN channel variable.
|
||||
|
||||
app_read
|
||||
------------------
|
||||
* A new option 'e' has been added to allow Read() to return the
|
||||
terminator as the dialed digits in the case where only the terminator
|
||||
is entered.
|
||||
|
||||
app_senddtmf
|
||||
------------------
|
||||
* A new option has been added to SendDTMF() which will answer the
|
||||
specified channel if it is not already up. If no channel is specified,
|
||||
the current channel will be answered instead.
|
||||
|
||||
app_signal
|
||||
------------------
|
||||
* Adds Signal and WaitForSignal applications
|
||||
which can be used for signaling or as a
|
||||
simple message queue in the dialplan.
|
||||
|
||||
func_json
|
||||
------------------
|
||||
* Additional parsing capabilities have been added to the
|
||||
JSON_DECODE function, including support for arrays
|
||||
and recursive indexing.
|
||||
|
||||
res_phoneprov
|
||||
------------------
|
||||
* On multihomed Asterisk servers with dynamic SERVER template variables,
|
||||
reloading this module is no longer required when re-provisioning your
|
||||
phone to another interface address (e.g. when moving between VLANs.)
|
||||
|
||||
res_pjsip_rfc3326
|
||||
------------------
|
||||
* Add ability to set HANGUPCAUSE when SIP causecode received in BYE Reason header (in
|
||||
addition to currently supported Q.850). The first header found will be used to set
|
||||
the HANGUPCAUSE variable.
|
||||
|
||||
res_pjsip_session
|
||||
------------------
|
||||
* The overlap_context option now allows explicitly
|
||||
specifying a context to use for overlap dialing matches.
|
||||
|
||||
res_rtp_asterisk
|
||||
------------------
|
||||
* This module has been updated to provide additional
|
||||
quality statistics in the form of an Asterisk
|
||||
Media Experience Score. The score is available using
|
||||
the same mechanisms you'd use to retrieve jitter, loss,
|
||||
and rtt statistics. For more information about the
|
||||
score and how to retrieve it, see
|
||||
https://wiki.asterisk.org/wiki/display/AST/Media+Experience+Score
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 20.0.0 to Asterisk 20.1.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
AMI
|
||||
------------------
|
||||
* The AOCMessage action can now be used to generate AOC-S messages.
|
||||
|
||||
Add support for named capture agent.
|
||||
------------------
|
||||
* A name for the capture agent can now be specified
|
||||
using the capture_name option which, if specified,
|
||||
will be sent to the HEP server.
|
||||
|
||||
app_if
|
||||
------------------
|
||||
* Adds the If, ElseIf, Else, EndIf, and ExitIf applications
|
||||
for conditional execution of a block of code.
|
||||
|
||||
app_mixmonitor
|
||||
------------------
|
||||
* The d option for MixMonitor now allows deleting
|
||||
the original recording when MixMonitor exits,
|
||||
which can be useful when MixMonitor copies it
|
||||
somewhere else before exiting.
|
||||
|
||||
* Adds the c option to use the real Caller ID on
|
||||
the channel in voicemail recordings as opposed
|
||||
to the Connected Line.
|
||||
|
||||
app_voicemail
|
||||
------------------
|
||||
* The voicemail user option attachextrecs can
|
||||
now be set to control whether external recordings
|
||||
trigger voicemail email notifications.
|
||||
|
||||
cdr
|
||||
------------------
|
||||
* Two new options have been added which allow
|
||||
bridging and dial state changes to be ignored
|
||||
in CDRs, which can be useful if a single CDR
|
||||
is desired for a channel.
|
||||
|
||||
chan_dahdi
|
||||
------------------
|
||||
* FXO channels (FXS signaled) that don't use callerid or
|
||||
distinctive ring detection can now be configured
|
||||
to enter the dialplan immediately using immediate=yes,
|
||||
instead of waiting for at least one ring.
|
||||
|
||||
pbx_builtins
|
||||
------------------
|
||||
* It is now possible to not wait for media on
|
||||
a channel when answering it using Answer,
|
||||
by specifying the i option.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Added options "security_negotiation" and "security_mechanisms" to pjsip
|
||||
endpoints and registrations. "security_negotiation" can be set to "no" (default)
|
||||
or "mediasec", and "security_mechanisms" can be a list of comma-separated
|
||||
security_mechanisms in the form defined by RFC 3329 section 2.2.
|
||||
|
||||
* A new option named "all_codecs_on_empty_reinvite" has been added to the
|
||||
global section. When this option is enabled, on reception of a re-INVITE
|
||||
without SDP, Asterisk will send an SDP offer in the 200 OK response containing
|
||||
all configured codecs on the endpoint, instead of simply those that have
|
||||
already been negotiated. RFC 3261 specifies this as a SHOULD requirement.
|
||||
The default value is "off".
|
||||
|
||||
res_pjsip_aoc
|
||||
------------------
|
||||
* Added res_pjsip_aoc which gives chan_pjsip the ability to send Advice-of-Charge messages.
|
||||
A new endpoint option, send_aoc, controls this.
|
||||
|
||||
res_pjsip_header_funcs
|
||||
------------------
|
||||
* The new PJSIP_HEADER_PARAM function now fully supports both
|
||||
URI and header parameters. Both reading and writing
|
||||
parameters are supported.
|
||||
|
||||
res_pjsip_logger
|
||||
------------------
|
||||
* SIP messages can now be filtered by SIP request method
|
||||
(INVITE, CANCEL, ACK, BYE, REGISTER, OPTION,
|
||||
SUBSCRIBE, NOTIFY, PUBLISH, INFO, and MESSAGE),
|
||||
allowing for more granular debugging to be done
|
||||
in the CLI. This applies to requests but not responses.
|
||||
|
||||
res_pjsip_notify
|
||||
------------------
|
||||
* Allows using the config options in pjsip_notify.conf
|
||||
from AMI actions as with the existing CLI commands.
|
||||
|
||||
res_tonedetect
|
||||
------------------
|
||||
* The TONE_DETECT function now supports
|
||||
detection of audible ringback tone
|
||||
using the p option.
|
||||
|
||||
xmldocs
|
||||
------------------
|
||||
* The XML documentation can now be reloaded without restarting
|
||||
Asterisk, which makes it possible to load new modules that
|
||||
enforce documentation without restarting Asterisk.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
New EXPORT function
|
||||
------------------
|
||||
* A new function, EXPORT, allows writing variables
|
||||
and functions on other channels, the complement
|
||||
of the IMPORT function.
|
||||
|
||||
app_amd
|
||||
------------------
|
||||
* An audio file to play during AMD processing can
|
||||
now be specified to the AMD application or configured
|
||||
in the amd.conf configuration file.
|
||||
|
||||
app_bridgewait
|
||||
------------------
|
||||
* Adds the n option to not answer the channel when
|
||||
the BridgeWait application is called.
|
||||
|
||||
features
|
||||
------------------
|
||||
* The Bridge application now has the n "no answer" option
|
||||
that can be used to prevent the channel from being
|
||||
automatically answered prior to bridging.
|
||||
|
||||
func_strings
|
||||
------------------
|
||||
* Three new functions, TRIM, LTRIM, and RTRIM, are
|
||||
now available for trimming leading and trailing
|
||||
whitespace.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* A new option named "peer_supported" has been added to the endpoint option
|
||||
100rel. When set to this option, Asterisk sends provisional responses
|
||||
reliably if the peer supports it. If the peer does not support reliable
|
||||
provisional responses, Asterisk sends them normally.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 19.0.0 to Asterisk 20.0.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Transfer feature
|
||||
------------------
|
||||
* The following capabilities have been added to the
|
||||
transfer feature:
|
||||
|
||||
- The transfer initiation announcement prompt can
|
||||
now be customized in features.conf.
|
||||
|
||||
- The TRANSFER_EXTEN variable now can be set on the
|
||||
transferer's channel in order to allow the transfer
|
||||
function to automatically attempt to go to the extension
|
||||
contained in this variable, if it exists. The transfer
|
||||
context behavior is not changed (TRANSFER_CONTEXT is used
|
||||
if it exists; otherwise the default context is used).
|
||||
|
||||
app_confbridge
|
||||
------------------
|
||||
* Adds the end_marked_any option which can be used
|
||||
to kick users from a conference after any
|
||||
marked user leaves (including marked users).
|
||||
|
||||
db
|
||||
------------------
|
||||
* The DBPrefixGet AMI action now allows retrieving
|
||||
all of the DB keys beginning with a particular
|
||||
prefix.
|
||||
|
||||
locks
|
||||
------------------
|
||||
* A new AMI event, DeadlockStart, is now available
|
||||
when Asterisk is compiled with DETECT_DEADLOCKS,
|
||||
and can indicate that a deadlock has occured.
|
||||
|
||||
res_geolocation
|
||||
------------------
|
||||
* * Added processing for the 'confidence' element.
|
||||
* Added documentation to some APIs.
|
||||
* removed a lot of complex code related to the very-off-nominal
|
||||
case of needing to process multiple location info sources.
|
||||
* Create a new 'ast_geoloc_eprofile_to_pidf' API that just takes
|
||||
one eprofile instead of a datastore of multiples.
|
||||
* Plugged a huge leak in XML processing that arose from
|
||||
insufficient documentation by the libxml/libxslt authors.
|
||||
* Refactored stylesheets to be more efficient.
|
||||
* Renamed 'profile_action' to 'profile_precedence' to better
|
||||
reflect it's purpose.
|
||||
* Added the config option for 'allow_routing_use' which
|
||||
sets the value of the 'Geolocation-Routing' header.
|
||||
* Removed the GeolocProfileCreate and GeolocProfileDelete
|
||||
dialplan apps.
|
||||
* Changed the GEOLOC_PROFILE dialplan function as follows:
|
||||
* Removed the 'profile' argument.
|
||||
* Automatically create a profile if it doesn't exist.
|
||||
* Delete a profile if 'inheritable' is set to no.
|
||||
* Fixed various bugs and leaks
|
||||
* Updated Asterisk WiKi documentation.
|
||||
|
||||
Added 4 built-in profiles:
|
||||
"<prefer_config>"
|
||||
"<discard_config>"
|
||||
"<prefer_incoming>"
|
||||
"<discard_incoming>"
|
||||
The profiles are empty except for having their precedence
|
||||
set.
|
||||
|
||||
Added profile parameter "suppress_empty_ca_elements" that
|
||||
will cause Civic Address elements that are empty to be
|
||||
suppressed from the outgoing PIDF-LO document.
|
||||
|
||||
You can now specify the location object's format, location_info,
|
||||
method, location_source and confidence parameters directly on
|
||||
a profile object for simple scenarios where the location
|
||||
information isn't common with any other profiles. This is
|
||||
mutually exclusive with setting location_reference on the
|
||||
profile.
|
||||
|
||||
Added an 'a' option to the GEOLOC_PROFILE function to allow
|
||||
variable lists like location_info_refinement to be appended
|
||||
to instead of replacing the entire list.
|
||||
|
||||
Added an 'r' option to the GEOLOC_PROFILE function to resolve all
|
||||
variables before a read operation and after a Set operation.
|
||||
|
||||
res_musiconhold_answeredonly
|
||||
------------------
|
||||
* This change adds an option, answeredonly, that will prevent music
|
||||
on hold on channels that are not answered.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* TLS transports in res_pjsip can now reload their TLS certificate
|
||||
and private key files, provided the filename of them has not
|
||||
changed.
|
||||
|
||||
Applications
|
||||
------------------
|
||||
* added support for Danish syntax, playing the correct plural sound file
|
File diff suppressed because it is too large
Load Diff
2
LICENSE
2
LICENSE
|
@ -45,7 +45,7 @@ redistribution of Asterisk source code obtained from Digium, you
|
|||
should contact our licensing department to determine the necessary
|
||||
steps you must take. For more information on this policy, please read:
|
||||
|
||||
https://www.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy.pdf
|
||||
https://www.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy-1.pdf
|
||||
|
||||
If you have any questions regarding our licensing policy, please
|
||||
contact us:
|
||||
|
|
15
Makefile
15
Makefile
|
@ -377,7 +377,7 @@ $(MOD_SUBDIRS_MENUSELECT_TREE):
|
|||
+@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo
|
||||
+@$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts
|
||||
|
||||
$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h
|
||||
$(SUBDIRS): makeopts .lastclean main/version.c include/asterisk/build.h defaults.h
|
||||
|
||||
ifeq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
main: third-party
|
||||
|
@ -403,7 +403,7 @@ defaults.h: makeopts .lastclean build_tools/make_defaults_h
|
|||
@cmp -s $@.tmp $@ || mv $@.tmp $@
|
||||
@rm -f $@.tmp
|
||||
|
||||
main/version.c: FORCE menuselect.makeopts .lastclean
|
||||
main/version.c: FORCE include/asterisk/buildopts.h menuselect.makeopts .lastclean
|
||||
@build_tools/make_version_c > $@.tmp
|
||||
@cmp -s $@.tmp $@ || mv $@.tmp $@
|
||||
@rm -f $@.tmp
|
||||
|
@ -545,7 +545,7 @@ INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTCACHEDIR)" "$(AS
|
|||
"$(ASTDATADIR)/firmware/iax" "$(ASTDATADIR)/images" "$(ASTDATADIR)/keys" \
|
||||
"$(ASTDATADIR)/phoneprov" "$(ASTDATADIR)/rest-api" "$(ASTDATADIR)/static-http" \
|
||||
"$(ASTDATADIR)/sounds" "$(ASTDATADIR)/moh" "$(ASTMANDIR)/man8" "$(AGI_DIR)" "$(ASTDBDIR)" \
|
||||
"$(ASTDATADIR)/third-party" "${ASTDATADIR}/keys/stir_shaken"
|
||||
"$(ASTDATADIR)/third-party" "${ASTDATADIR}/keys/stir_shaken" "${ASTDATADIR}/keys/stir_shaken/cache"
|
||||
|
||||
installdirs:
|
||||
@for i in $(INSTALLDIRS); do \
|
||||
|
@ -561,9 +561,9 @@ bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
|
|||
$(INSTALL) -m 755 contrib/scripts/astversion "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
$(INSTALL) -m 755 contrib/scripts/astgenkey "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
$(INSTALL) -m 755 contrib/scripts/autosupport "$(DESTDIR)$(ASTSBINDIR)/"
|
||||
if [ ! -f /sbin/launchd ]; then \
|
||||
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk"; \
|
||||
fi
|
||||
ifneq ($(HAVE_SBIN_LAUNCHD),1)
|
||||
./build_tools/install_subst contrib/scripts/safe_asterisk "$(DESTDIR)$(ASTSBINDIR)/safe_asterisk";
|
||||
endif
|
||||
|
||||
ifneq ($(DISABLE_XMLDOC),yes)
|
||||
$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"
|
||||
|
@ -1119,7 +1119,8 @@ ifeq ($(PYTHON),:)
|
|||
else
|
||||
@$(INSTALL) -d doc/rest-api
|
||||
$(PYTHON) rest-api-templates/make_ari_stubs.py \
|
||||
rest-api/resources.json .
|
||||
--resources rest-api/resources.json --source-dir $(ASTTOPDIR) \
|
||||
--dest-dir $(ASTTOPDIR)/doc/rest-api --docs-prefix ../
|
||||
endif
|
||||
|
||||
check-alembic: makeopts
|
||||
|
|
|
@ -213,10 +213,10 @@ endif
|
|||
# extern const size_t _binary_abc_def_xml_size;
|
||||
%.o: %.xml
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
|
||||
%.o: %.xslt
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) -g -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
$(CMD_PREFIX) $(CC) -g -Wl,-znoexecstack -nostartfiles -nodefaultlibs -nostdlib -r -Wl,-b,binary -o $@ $^
|
||||
|
||||
dist-clean:: clean
|
||||
|
|
|
@ -377,9 +377,8 @@ is set to no.
|
|||
|
||||
In Asterisk 12 and later, live_dangerously defaults to no.
|
||||
|
||||
|
||||
[voip-security-webinar]: https://www.asterisk.org/security/webinar/
|
||||
[blog-sip-security]: http://blogs.digium.com/2009/03/28/sip-security/
|
||||
[voip-security-webinar]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/Asterisk-Security-Webinars/
|
||||
[blog-sip-security]: https://web.archive.org/web/20171030134647/http://blogs.digium.com/2009/03/28/sip-security/
|
||||
[Strong Password Generator]: https://www.strongpasswordgenerator.com
|
||||
[Filtering Data]: #filtering-data
|
||||
[Proper Device Naming]: #proper-device-naming
|
||||
|
@ -387,4 +386,4 @@ In Asterisk 12 and later, live_dangerously defaults to no.
|
|||
[Reducing Pattern Match Typos]: #reducing-pattern-match-typos
|
||||
[Manager Class Authorizations]: #manager-class-authorizations
|
||||
[Avoid Privilege Escalations]: #avoid-privilege-escalations
|
||||
[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations
|
||||
[Important Security Considerations]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/
|
||||
|
|
|
@ -20,7 +20,7 @@ more telephony interfaces than just Internet telephony. Asterisk also has a
|
|||
vast amount of support for traditional PSTN telephony, as well.
|
||||
|
||||
For more information on the project itself, please visit the Asterisk
|
||||
[home page] and the official [wiki]. In addition you'll find lots
|
||||
[home page] and the official [documentation]. In addition you'll find lots
|
||||
of information compiled by the Asterisk community at [voip-info.org].
|
||||
|
||||
There is a book on Asterisk published by O'Reilly under the Creative Commons
|
||||
|
@ -48,7 +48,7 @@ ANY special hardware, not even a sound card) to install and run Asterisk.
|
|||
|
||||
Supported telephony hardware includes:
|
||||
* All Analog and Digital Interface cards from [Sangoma]
|
||||
* QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
|
||||
* QuickNet Internet PhoneJack and LineJack
|
||||
* any full duplex sound card supported by ALSA, OSS, or PortAudio
|
||||
* any ISDN card supported by mISDN on Linux
|
||||
* The Xorcom Astribank channel bank
|
||||
|
@ -258,7 +258,7 @@ Asterisk is a trademark of Sangoma Technologies Corporation
|
|||
|
||||
[home page]: https://www.asterisk.org
|
||||
[support]: https://www.asterisk.org/support
|
||||
[wiki]: https://wiki.asterisk.org/
|
||||
[documentation]: https://docs.asterisk.org/
|
||||
[mailing list]: http://lists.digium.com/mailman/listinfo/asterisk-users
|
||||
[chan_dahdi.conf]: configs/samples/chan_dahdi.conf.sample
|
||||
[voip-info.org]: http://www.voip-info.org/wiki-Asterisk
|
||||
|
@ -269,4 +269,4 @@ Asterisk is a trademark of Sangoma Technologies Corporation
|
|||
[CHANGES]: CHANGES
|
||||
[configs]: configs
|
||||
[doc]: doc
|
||||
[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations
|
||||
[Important Security Considerations]: https://docs.asterisk.org/Deployment/Important-Security-Considerations/
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The Asterisk project maintains a [documentation page](https://docs.asterisk.org/About-the-Project/Asterisk-Versions/) of releases. Each version is listed with its release date, security fix only date, and end of life date. Consult this wiki page to see if the version of Asterisk you are reporting a security vulnerability against is still supported.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a vulnerability use the "Report a vulnerability" button under the "Security" tab of this project.
|
2986
UPGRADE.txt
2986
UPGRADE.txt
File diff suppressed because it is too large
Load Diff
|
@ -192,11 +192,13 @@ EXTERN int ooQ931Decode
|
|||
screening indicators ;-) */
|
||||
if(ie->discriminator == Q931CallingPartyNumberIE)
|
||||
{
|
||||
int numoffset=1;
|
||||
OOTRACEDBGB1(" CallingPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
|
||||
if( (ie->length >= numoffset) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
int numoffset=1;
|
||||
if(!(0x80 & ie->data[0])) numoffset = 2;
|
||||
memcpy(number, ie->data+numoffset,ie->length-numoffset);
|
||||
number[ie->length-numoffset]='\0';
|
||||
OOTRACEDBGB2(" %s\n", number);
|
||||
|
@ -204,7 +206,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCallingPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
@ -214,7 +216,8 @@ EXTERN int ooQ931Decode
|
|||
if(ie->discriminator == Q931CalledPartyNumberIE)
|
||||
{
|
||||
OOTRACEDBGB1(" CalledPartyNumber IE = {\n");
|
||||
if(ie->length < OO_MAX_NUMBER_LENGTH)
|
||||
if( (ie->length >= 1) &&
|
||||
(ie->length < OO_MAX_NUMBER_LENGTH) )
|
||||
{
|
||||
memcpy(number, ie->data+1,ie->length-1);
|
||||
number[ie->length-1]='\0';
|
||||
|
@ -223,7 +226,7 @@ EXTERN int ooQ931Decode
|
|||
ooCallSetCalledPartyNumber(call, number);
|
||||
}
|
||||
else{
|
||||
OOTRACEERR3("Error:Calling party number too long. (%s, %s)\n",
|
||||
OOTRACEERR3("Error:Calling party number outside range. (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
}
|
||||
OOTRACEDBGB1(" }\n");
|
||||
|
|
|
@ -92,6 +92,12 @@
|
|||
<para>Is the maximum duration of a word to accept.</para>
|
||||
<para>If exceeded, then the result is detection as a MACHINE</para>
|
||||
</parameter>
|
||||
<parameter name="audioFile" required="false">
|
||||
<para>Is an audio file to play to the caller while AMD is in progress.</para>
|
||||
<para>By default, no audio file is played.</para>
|
||||
<para>If an audio file is configured in amd.conf, then that file will be used
|
||||
if one is not specified here. That file may be overridden by this argument.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This application attempts to detect answering machines at the beginning
|
||||
|
@ -155,6 +161,9 @@ static int dfltBetweenWordsSilence = 50;
|
|||
static int dfltMaximumNumberOfWords = 2;
|
||||
static int dfltSilenceThreshold = 256;
|
||||
static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
|
||||
static char *dfltAudioFile = NULL;
|
||||
|
||||
static ast_mutex_t config_lock;
|
||||
|
||||
/* Set to the lowest ms value provided in amd.conf or application parameters */
|
||||
static int dfltMaxWaitTimeForFrame = 50;
|
||||
|
@ -179,7 +188,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
char amdCause[256] = "", amdStatus[256] = "";
|
||||
char *parse = ast_strdupa(data);
|
||||
|
||||
/* Lets set the initial values of the variables that will control the algorithm.
|
||||
/* Let's set the initial values of the variables that will control the algorithm.
|
||||
The initial values are the default ones. If they are passed as arguments
|
||||
when invoking the application, then the default values will be overwritten
|
||||
by the ones passed as parameters. */
|
||||
|
@ -193,6 +202,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
int silenceThreshold = dfltSilenceThreshold;
|
||||
int maximumWordLength = dfltMaximumWordLength;
|
||||
int maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
|
||||
const char *audioFile = NULL;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(argInitialSilence);
|
||||
|
@ -204,8 +214,15 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
AST_APP_ARG(argMaximumNumberOfWords);
|
||||
AST_APP_ARG(argSilenceThreshold);
|
||||
AST_APP_ARG(argMaximumWordLength);
|
||||
AST_APP_ARG(audioFile);
|
||||
);
|
||||
|
||||
ast_mutex_lock(&config_lock);
|
||||
if (!ast_strlen_zero(dfltAudioFile)) {
|
||||
audioFile = ast_strdupa(dfltAudioFile);
|
||||
}
|
||||
ast_mutex_unlock(&config_lock);
|
||||
|
||||
ast_verb(3, "AMD: %s %s %s (Fmt: %s)\n", ast_channel_name(chan),
|
||||
S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "(N/A)"),
|
||||
S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "(N/A)"),
|
||||
|
@ -233,6 +250,9 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
silenceThreshold = atoi(args.argSilenceThreshold);
|
||||
if (!ast_strlen_zero(args.argMaximumWordLength))
|
||||
maximumWordLength = atoi(args.argMaximumWordLength);
|
||||
if (!ast_strlen_zero(args.audioFile)) {
|
||||
audioFile = args.audioFile;
|
||||
}
|
||||
} else {
|
||||
ast_debug(1, "AMD using the default parameters.\n");
|
||||
}
|
||||
|
@ -280,6 +300,11 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
/* Set our start time so we can tie the loop to real world time and not RTP updates */
|
||||
amd_tvstart = ast_tvnow();
|
||||
|
||||
/* Optional audio file to play to caller while AMD is doing its thing. */
|
||||
if (!ast_strlen_zero(audioFile)) {
|
||||
ast_streamfile(chan, audioFile, ast_channel_language(chan));
|
||||
}
|
||||
|
||||
/* Now we go into a loop waiting for frames from the channel */
|
||||
while ((res = ast_waitfor(chan, 2 * maxWaitTimeForFrame)) > -1) {
|
||||
int ms = 0;
|
||||
|
@ -462,10 +487,14 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
/* Free the DSP used to detect silence */
|
||||
ast_dsp_free(silenceDetector);
|
||||
|
||||
/* If we were playing something to pass the time, stop it now. */
|
||||
if (!ast_strlen_zero(audioFile)) {
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static int amd_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
isAnsweringMachine(chan, data);
|
||||
|
@ -516,7 +545,16 @@ static int load_config(int reload)
|
|||
dfltMaximumNumberOfWords = atoi(var->value);
|
||||
} else if (!strcasecmp(var->name, "maximum_word_length")) {
|
||||
dfltMaximumWordLength = atoi(var->value);
|
||||
|
||||
} else if (!strcasecmp(var->name, "playback_file")) {
|
||||
ast_mutex_lock(&config_lock);
|
||||
if (dfltAudioFile) {
|
||||
ast_free(dfltAudioFile);
|
||||
dfltAudioFile = NULL;
|
||||
}
|
||||
if (!ast_strlen_zero(var->value)) {
|
||||
dfltAudioFile = ast_strdup(var->value);
|
||||
}
|
||||
ast_mutex_unlock(&config_lock);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
|
||||
app, cat, var->name, var->lineno);
|
||||
|
@ -529,7 +567,7 @@ static int load_config(int reload)
|
|||
|
||||
ast_config_destroy(cfg);
|
||||
|
||||
ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
|
||||
ast_verb(5, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
|
||||
"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
|
||||
dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
|
||||
dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
|
||||
|
@ -539,6 +577,12 @@ static int load_config(int reload)
|
|||
|
||||
static int unload_module(void)
|
||||
{
|
||||
ast_mutex_lock(&config_lock);
|
||||
if (dfltAudioFile) {
|
||||
ast_free(dfltAudioFile);
|
||||
}
|
||||
ast_mutex_unlock(&config_lock);
|
||||
ast_mutex_destroy(&config_lock);
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
|
@ -554,6 +598,7 @@ static int unload_module(void)
|
|||
*/
|
||||
static int load_module(void)
|
||||
{
|
||||
ast_mutex_init(&config_lock);
|
||||
if (load_config(0) || ast_register_application_xml(app, amd_exec)) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
</syntax>
|
||||
<description>
|
||||
<para>Connects to the given TCP service, then transmits channel audio over that socket. In turn, audio is received from the socket and sent to the channel. Only audio frames will be transmitted.</para>
|
||||
<para>Protocol is specified at https://wiki.asterisk.org/wiki/display/AST/AudioSocket</para>
|
||||
<para>Protocol is specified at https://docs.asterisk.org/Configuration/Channel-Drivers/AudioSocket/</para>
|
||||
<para>This application does not automatically answer and should generally be preceeded by an application such as Answer() or Progress().</para>
|
||||
</description>
|
||||
</application>
|
||||
|
@ -180,7 +180,7 @@ static int audiosocket_run(struct ast_channel *chan, const char *id, int svc)
|
|||
chanName = ast_channel_name(chan);
|
||||
|
||||
while (1) {
|
||||
|
||||
ms = -1;
|
||||
targetChan = ast_waitfor_nandfds(&chan, 1, &svc, 1, NULL, &outfd, &ms);
|
||||
if (targetChan) {
|
||||
f = ast_read(chan);
|
||||
|
|
|
@ -95,8 +95,17 @@ static const char app[] = "Authenticate";
|
|||
maxdigits have been entered (without requiring the user to press the <literal>#</literal> key).
|
||||
Defaults to 0 - no limit - wait for the user press the <literal>#</literal> key.</para>
|
||||
</parameter>
|
||||
<parameter name="prompt" required="false">
|
||||
<para>Override the agent-pass prompt file.</para>
|
||||
<parameter name="prompt" required="false" argsep="&">
|
||||
<para>Override the "agent-pass" sound file. Can be
|
||||
an ampersand separated list of filenames. If the filename
|
||||
is a relative filename (it does not begin with a slash), it
|
||||
will be searched for in the Asterisk sounds directory. If the
|
||||
filename is able to be parsed as a URL, Asterisk will
|
||||
download the file and then begin playback on it. To include a
|
||||
literal <literal>&</literal> in the URL you can enclose
|
||||
the URL in single quotes.</para>
|
||||
<argument name="prompt" required="true" />
|
||||
<argument name="prompt2" multiple="true" />
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
|
|
|
@ -100,6 +100,9 @@
|
|||
<para>Automatically exit the bridge and return to the PBX after
|
||||
<emphasis>duration</emphasis> seconds.</para>
|
||||
</option>
|
||||
<option name="n">
|
||||
<para>Do not automatically answer the channel.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
|
@ -108,7 +111,7 @@
|
|||
The channel will then wait in the holding bridge until some event occurs
|
||||
which removes it from the holding bridge.</para>
|
||||
<note><para>This application will answer calls which haven't already
|
||||
been answered.</para></note>
|
||||
been answered, unless the n option is provided.</para></note>
|
||||
</description>
|
||||
</application>
|
||||
***/
|
||||
|
@ -186,6 +189,7 @@ enum bridgewait_flags {
|
|||
MUXFLAG_MOHCLASS = (1 << 0),
|
||||
MUXFLAG_ENTERTAINMENT = (1 << 1),
|
||||
MUXFLAG_TIMEOUT = (1 << 2),
|
||||
MUXFLAG_NOANSWER = (1 << 3),
|
||||
};
|
||||
|
||||
enum bridgewait_args {
|
||||
|
@ -199,6 +203,7 @@ AST_APP_OPTIONS(bridgewait_opts, {
|
|||
AST_APP_OPTION_ARG('e', MUXFLAG_ENTERTAINMENT, OPT_ARG_ENTERTAINMENT),
|
||||
AST_APP_OPTION_ARG('m', MUXFLAG_MOHCLASS, OPT_ARG_MOHCLASS),
|
||||
AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT),
|
||||
AST_APP_OPTION('n', MUXFLAG_NOANSWER),
|
||||
});
|
||||
|
||||
static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
|
||||
|
@ -458,7 +463,7 @@ static int bridgewait_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
|
||||
/* Answer the channel if needed */
|
||||
if (ast_channel_state(chan) != AST_STATE_UP) {
|
||||
if (ast_channel_state(chan) != AST_STATE_UP && !ast_test_flag(&flags, MUXFLAG_NOANSWER)) {
|
||||
ast_answer(chan);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,619 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2022, Naveen Albert
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Channel audio broadcasting
|
||||
*
|
||||
* \author Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>extended</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/autochan.h"
|
||||
#include "asterisk/format_cache.h"
|
||||
#include "asterisk/cli.h" /* use ESS macro */
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="Broadcast" language="en_US">
|
||||
<synopsis>
|
||||
Transmit or receive audio to or from multiple channels simultaneously
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="options">
|
||||
<optionlist>
|
||||
<option name="b">
|
||||
<para>In addition to broadcasting to target channels, also
|
||||
broadcast to any channels to which target channels are bridged.</para>
|
||||
</option>
|
||||
<option name="l">
|
||||
<para>Allow usage of a long queue to store audio frames.</para>
|
||||
<note><para>This may introduce some delay in the received audio feed, but will improve the audio quality.</para></note>
|
||||
</option>
|
||||
<option name="o">
|
||||
<para>Do not mix streams when combining audio from target channels (only applies with s option).</para>
|
||||
</option>
|
||||
<option name="r">
|
||||
<para>Feed frames to barge channels in "reverse" by injecting them into the primary channel's read queue instead.</para>
|
||||
<para>This option is required for barge to work in a n-party bridge (but not for 2-party bridges). Alternately, you
|
||||
can add an intermediate channel by using a non-optimized Local channel, so that the target channel is bridged with
|
||||
a single channel that is connected to the bridge, but it is recommended this option be used instead.</para>
|
||||
<para>Note that this option will always feed injected audio to the other party, regardless of whether the target
|
||||
channel is bridged or not.</para>
|
||||
</option>
|
||||
<option name="s">
|
||||
<para>Rather than broadcast audio to a bunch of channels, receive the combined audio from the target channels.</para>
|
||||
</option>
|
||||
<option name="w">
|
||||
<para>Broadcast audio received on this channel to other channels.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
<parameter name="channels" required="true" argsep=",">
|
||||
<para>List of channels for broadcast targets.</para>
|
||||
<para>Channel names must be the full channel names, not merely device names.</para>
|
||||
<para>Broadcasting will continue until the broadcasting channel hangs up or all target channels have hung up.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This application can be used to broadcast audio to multiple channels at once.
|
||||
Any audio received on this channel will be transmitted to all of the specified channels and, optionally, their bridged peers.</para>
|
||||
<para>It can also be used to aggregate audio from multiple channels at once.
|
||||
Any audio on any of the specified channels, and optionally their bridged peers, will be transmitted to this channel.</para>
|
||||
<para>Execution of the application continues until either the broadcasting channel hangs up
|
||||
or all specified channels have hung up.</para>
|
||||
<para>This application is used for one-to-many and many-to-one audio applications where
|
||||
bridge mixing cannot be done synchronously on all the involved channels.
|
||||
This is primarily useful for injecting the same audio stream into multiple channels at once,
|
||||
or doing the reverse, combining the audio from multiple channels into a single stream.
|
||||
This contrasts with using a separate injection channel for each target channel and/or
|
||||
using a conference bridge.</para>
|
||||
<para>The channel running the Broadcast application must do so synchronously. The specified channels,
|
||||
however, may be doing other things.</para>
|
||||
<example title="Broadcast received audio to three channels and their bridged peers">
|
||||
same => n,Broadcast(wb,DAHDI/1,DAHDI/3,PJSIP/doorphone)
|
||||
</example>
|
||||
<example title="Broadcast received audio to three channels, only">
|
||||
same => n,Broadcast(w,DAHDI/1,DAHDI/3,PJSIP/doorphone)
|
||||
</example>
|
||||
<example title="Combine audio from three channels and their bridged peers to us">
|
||||
same => n,Broadcast(s,DAHDI/1,DAHDI/3,PJSIP/doorphone)
|
||||
</example>
|
||||
<example title="Combine audio from three channels to us">
|
||||
same => n,Broadcast(so,DAHDI/1,DAHDI/3,PJSIP/doorphone)
|
||||
</example>
|
||||
<example title="Two-way audio with a bunch of channels">
|
||||
same => n,Broadcast(wbso,DAHDI/1,DAHDI/3,PJSIP/doorphone)
|
||||
</example>
|
||||
<para>Note that in the last example above, this is NOT the same as a conference bridge.
|
||||
The specified channels are not audible to each other, only to the channel running the
|
||||
Broadcast application. The two-way audio is only between the broadcasting channel and
|
||||
each of the specified channels, individually.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">ChanSpy</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static const char app_broadcast[] = "Broadcast";
|
||||
|
||||
enum {
|
||||
OPTION_READONLY = (1 << 0), /* Don't mix the two channels */
|
||||
OPTION_BARGE = (1 << 1), /* Barge mode (whisper to both channels) */
|
||||
OPTION_LONG_QUEUE = (1 << 2), /* Allow usage of a long queue to store audio frames. */
|
||||
OPTION_WHISPER = (1 << 3),
|
||||
OPTION_SPY = (1 << 4),
|
||||
OPTION_REVERSE_FEED = (1 << 5),
|
||||
OPTION_ANSWER_WARN = (1 << 6), /* Internal flag, not set by user */
|
||||
};
|
||||
|
||||
AST_APP_OPTIONS(spy_opts, {
|
||||
AST_APP_OPTION('b', OPTION_BARGE),
|
||||
AST_APP_OPTION('l', OPTION_LONG_QUEUE),
|
||||
AST_APP_OPTION('o', OPTION_READONLY),
|
||||
AST_APP_OPTION('r', OPTION_REVERSE_FEED),
|
||||
AST_APP_OPTION('s', OPTION_SPY),
|
||||
AST_APP_OPTION('w', OPTION_WHISPER),
|
||||
});
|
||||
|
||||
struct multi_autochan {
|
||||
char *name;
|
||||
struct ast_autochan *autochan;
|
||||
struct ast_autochan *bridge_autochan;
|
||||
struct ast_audiohook whisper_audiohook;
|
||||
struct ast_audiohook bridge_whisper_audiohook;
|
||||
struct ast_audiohook spy_audiohook;
|
||||
unsigned int connected:1;
|
||||
unsigned int bridge_connected:1;
|
||||
unsigned int spying:1;
|
||||
AST_LIST_ENTRY(multi_autochan) entry; /*!< Next record */
|
||||
};
|
||||
|
||||
AST_RWLIST_HEAD(multi_autochan_list, multi_autochan);
|
||||
|
||||
struct multi_spy {
|
||||
struct multi_autochan_list *chanlist;
|
||||
unsigned int readonly:1;
|
||||
};
|
||||
|
||||
static void *spy_alloc(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return data; /* just store the data pointer in the channel structure */
|
||||
}
|
||||
|
||||
static void spy_release(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct multi_spy *multispy = data;
|
||||
struct multi_autochan_list *chanlist = multispy->chanlist;
|
||||
struct multi_autochan *mac;
|
||||
struct ast_frame *f;
|
||||
short *data1, *data2;
|
||||
int res, i;
|
||||
|
||||
/* All the frames we get are slin, so they will all have the same number of samples. */
|
||||
static const int num_samples = 160;
|
||||
short combine_buf[num_samples];
|
||||
struct ast_frame wf = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.offset = 0,
|
||||
.subclass.format = ast_format_slin,
|
||||
.datalen = num_samples * 2,
|
||||
.samples = num_samples,
|
||||
.src = __FUNCTION__,
|
||||
};
|
||||
|
||||
memset(&combine_buf, 0, sizeof(combine_buf));
|
||||
wf.data.ptr = combine_buf;
|
||||
|
||||
AST_RWLIST_WRLOCK(chanlist);
|
||||
AST_RWLIST_TRAVERSE_SAFE_BEGIN(chanlist, mac, entry) {
|
||||
ast_audiohook_lock(&mac->spy_audiohook);
|
||||
if (mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
ast_audiohook_unlock(&mac->spy_audiohook); /* Channel is already gone more than likely, the broadcasting channel will clean this up. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (multispy->readonly) { /* Option 'o' was set, so don't mix channel audio */
|
||||
f = ast_audiohook_read_frame(&mac->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, ast_format_slin);
|
||||
} else {
|
||||
f = ast_audiohook_read_frame(&mac->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_slin);
|
||||
}
|
||||
ast_audiohook_unlock(&mac->spy_audiohook);
|
||||
|
||||
if (!f) {
|
||||
continue; /* No frame? No problem. */
|
||||
}
|
||||
|
||||
/* Mix the samples. */
|
||||
for (i = 0, data1 = combine_buf, data2 = f->data.ptr; i < num_samples; i++, data1++, data2++) {
|
||||
ast_slinear_saturated_add(data1, data2);
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
AST_RWLIST_TRAVERSE_SAFE_END;
|
||||
AST_RWLIST_UNLOCK(chanlist);
|
||||
|
||||
res = ast_write(chan, &wf);
|
||||
ast_frfree(&wf);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct ast_generator spygen = {
|
||||
.alloc = spy_alloc,
|
||||
.release = spy_release,
|
||||
.generate = spy_generate,
|
||||
};
|
||||
|
||||
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_autochan_channel_lock(autochan);
|
||||
ast_debug(1, "Attaching spy channel %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
|
||||
|
||||
if (ast_test_flag(flags, OPTION_READONLY)) {
|
||||
ast_set_flag(audiohook, AST_AUDIOHOOK_MUTE_WRITE);
|
||||
} else {
|
||||
ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
|
||||
}
|
||||
if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
|
||||
ast_debug(2, "Using a long queue to store audio frames in spy audiohook\n");
|
||||
} else {
|
||||
ast_set_flag(audiohook, AST_AUDIOHOOK_SMALL_QUEUE);
|
||||
}
|
||||
res = ast_audiohook_attach(autochan->chan, audiohook);
|
||||
ast_autochan_channel_unlock(autochan);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan,
|
||||
struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
|
||||
{
|
||||
int retval = 0;
|
||||
struct ast_autochan *internal_bridge_autochan;
|
||||
struct ast_channel *spyee_chan;
|
||||
RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
|
||||
|
||||
ast_autochan_channel_lock(spyee_autochan);
|
||||
spyee_chan = ast_channel_ref(spyee_autochan->chan);
|
||||
ast_autochan_channel_unlock(spyee_autochan);
|
||||
|
||||
/* Note that ast_channel_bridge_peer only returns non-NULL for 2-party bridges, not n-party bridges (e.g. ConfBridge) */
|
||||
bridged = ast_channel_bridge_peer(spyee_chan);
|
||||
ast_channel_unref(spyee_chan);
|
||||
if (!bridged) {
|
||||
ast_debug(9, "Channel %s is not yet bridged, unable to setup barge\n", ast_channel_name(spyee_chan));
|
||||
/* If we're bridged, but it's not a 2-party bridge, then we probably should have used OPTION_REVERSE_FEED. */
|
||||
if (ast_test_flag(flags, OPTION_ANSWER_WARN) && ast_channel_is_bridged(spyee_chan)) {
|
||||
ast_clear_flag(flags, OPTION_ANSWER_WARN); /* Don't warn more than once. */
|
||||
ast_log(LOG_WARNING, "Barge failed: channel is bridged, but not to a 2-party bridge. Use the 'r' option.\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
|
||||
internal_bridge_autochan = ast_autochan_setup(bridged);
|
||||
if (!internal_bridge_autochan) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
|
||||
ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
*spyee_bridge_autochan = internal_bridge_autochan;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void multi_autochan_free(struct multi_autochan *mac)
|
||||
{
|
||||
if (mac->connected) {
|
||||
if (mac->whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
ast_debug(2, "Whisper audiohook no longer running\n");
|
||||
}
|
||||
ast_audiohook_lock(&mac->whisper_audiohook);
|
||||
ast_audiohook_detach(&mac->whisper_audiohook);
|
||||
ast_audiohook_unlock(&mac->whisper_audiohook);
|
||||
ast_audiohook_destroy(&mac->whisper_audiohook);
|
||||
}
|
||||
if (mac->bridge_connected) {
|
||||
if (mac->bridge_whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
ast_debug(2, "Whisper (bridged) audiohook no longer running\n");
|
||||
}
|
||||
ast_audiohook_lock(&mac->bridge_whisper_audiohook);
|
||||
ast_audiohook_detach(&mac->bridge_whisper_audiohook);
|
||||
ast_audiohook_unlock(&mac->bridge_whisper_audiohook);
|
||||
ast_audiohook_destroy(&mac->bridge_whisper_audiohook);
|
||||
}
|
||||
if (mac->spying) {
|
||||
if (mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
ast_debug(2, "Spy audiohook no longer running\n");
|
||||
}
|
||||
ast_audiohook_lock(&mac->spy_audiohook);
|
||||
ast_audiohook_detach(&mac->spy_audiohook);
|
||||
ast_audiohook_unlock(&mac->spy_audiohook);
|
||||
ast_audiohook_destroy(&mac->spy_audiohook);
|
||||
}
|
||||
if (mac->name) {
|
||||
int total = mac->connected + mac->bridge_connected + mac->spying;
|
||||
ast_debug(1, "Removing channel %s from target list (%d hook%s)\n", mac->name, total, ESS(total));
|
||||
ast_free(mac->name);
|
||||
}
|
||||
if (mac->autochan) {
|
||||
ast_autochan_destroy(mac->autochan);
|
||||
}
|
||||
if (mac->bridge_autochan) {
|
||||
ast_autochan_destroy(mac->bridge_autochan);
|
||||
}
|
||||
ast_free(mac);
|
||||
}
|
||||
|
||||
static int do_broadcast(struct ast_channel *chan, struct ast_flags *flags, const char *channels)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_frame *f;
|
||||
struct ast_silence_generator *silgen = NULL;
|
||||
struct multi_spy multispy;
|
||||
struct multi_autochan_list chanlist;
|
||||
struct multi_autochan *mac;
|
||||
int numchans = 0;
|
||||
int readonly = ast_test_flag(flags, OPTION_READONLY) ? 1 : 0;
|
||||
char *next, *chansdup = ast_strdupa(channels);
|
||||
|
||||
AST_RWLIST_HEAD_INIT(&chanlist);
|
||||
ast_channel_set_flag(chan, AST_FLAG_SPYING);
|
||||
|
||||
ast_set_flag(flags, OPTION_ANSWER_WARN); /* Initialize answer warn to 1 */
|
||||
|
||||
/* Hey, look ma, no list lock needed! Sometimes, it's nice to not have to share... */
|
||||
|
||||
/* Build a list of targets */
|
||||
while ((next = strsep(&chansdup, ","))) {
|
||||
struct ast_channel *ochan;
|
||||
if (ast_strlen_zero(next)) {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(next, ast_channel_name(chan))) {
|
||||
ast_log(LOG_WARNING, "Refusing to broadcast to ourself: %s\n", next);
|
||||
continue;
|
||||
}
|
||||
ochan = ast_channel_get_by_name(next);
|
||||
if (!ochan) {
|
||||
ast_log(LOG_WARNING, "No such channel: %s\n", next);
|
||||
continue;
|
||||
}
|
||||
/* Append to end of list. */
|
||||
if (!(mac = ast_calloc(1, sizeof(*mac)))) {
|
||||
ast_log(LOG_WARNING, "Multi autochan allocation failure\n");
|
||||
continue;
|
||||
}
|
||||
mac->name = ast_strdup(next);
|
||||
mac->autochan = ast_autochan_setup(ochan);
|
||||
if (!mac->name || !mac->autochan) {
|
||||
multi_autochan_free(mac);
|
||||
continue;
|
||||
}
|
||||
if (ast_test_flag(flags, OPTION_WHISPER)) {
|
||||
mac->connected = 1;
|
||||
ast_audiohook_init(&mac->whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Broadcast", 0);
|
||||
/* Inject audio from our channel to this target. */
|
||||
if (start_spying(mac->autochan, next, &mac->whisper_audiohook, flags)) {
|
||||
ast_log(LOG_WARNING, "Unable to attach whisper audiohook to %s\n", next);
|
||||
multi_autochan_free(mac);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ast_test_flag(flags, OPTION_SPY)) {
|
||||
mac->spying = 1;
|
||||
ast_audiohook_init(&mac->spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "Broadcast", 0);
|
||||
if (start_spying(mac->autochan, next, &mac->spy_audiohook, flags)) {
|
||||
ast_log(LOG_WARNING, "Unable to attach spy audiohook to %s\n", next);
|
||||
multi_autochan_free(mac);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
AST_RWLIST_INSERT_TAIL(&chanlist, mac, entry);
|
||||
numchans++;
|
||||
ochan = ast_channel_unref(ochan);
|
||||
}
|
||||
|
||||
ast_verb(4, "Broadcasting to %d channel%s on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
|
||||
ast_debug(1, "Broadcasting: (TX->1) whisper=%d, (TX->2) barge=%d, (RX<-%d) spy=%d (%s)\n",
|
||||
ast_test_flag(flags, OPTION_WHISPER) ? 1 : 0,
|
||||
ast_test_flag(flags, OPTION_BARGE) ? 1 : 0,
|
||||
readonly ? 1 : 2,
|
||||
ast_test_flag(flags, OPTION_SPY) ? 1 : 0,
|
||||
readonly ? "single" : "both");
|
||||
|
||||
if (ast_test_flag(flags, OPTION_SPY)) {
|
||||
multispy.chanlist = &chanlist;
|
||||
multispy.readonly = readonly;
|
||||
ast_activate_generator(chan, &spygen, &multispy);
|
||||
} else {
|
||||
/* We're not expecting to read any audio, just broadcast audio to a bunch of other channels. */
|
||||
silgen = ast_channel_start_silence_generator(chan);
|
||||
}
|
||||
|
||||
while (numchans && ast_waitfor(chan, -1) > 0) {
|
||||
int fres = 0;
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
ast_debug(1, "Channel %s must have hung up\n", ast_channel_name(chan));
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (f->frametype != AST_FRAME_VOICE) { /* Ignore any non-voice frames */
|
||||
ast_frfree(f);
|
||||
continue;
|
||||
}
|
||||
/* Write the frame to all our targets. */
|
||||
AST_RWLIST_WRLOCK(&chanlist);
|
||||
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac, entry) {
|
||||
/* Note that if no media is received, execution is suspended, but assuming continuous or
|
||||
* or frequent audio on the broadcasting channel, we'll quickly enough detect hung up targets.
|
||||
* This isn't really an issue, just something that might be confusing at first, but this is
|
||||
* due to the limitation with audiohooks of using the channel for timing. */
|
||||
if ((ast_test_flag(flags, OPTION_WHISPER) && mac->whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
|
||||
|| (ast_test_flag(flags, OPTION_SPY) && mac->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
|
||||
|| (mac->bridge_connected && ast_test_flag(flags, OPTION_BARGE) && mac->bridge_whisper_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)) {
|
||||
/* Even if we're spying only and not actually broadcasting audio, we need to detect channel hangup. */
|
||||
AST_RWLIST_REMOVE_CURRENT(entry);
|
||||
ast_debug(2, "Looks like %s has hung up\n", mac->name);
|
||||
multi_autochan_free(mac);
|
||||
numchans--;
|
||||
ast_debug(2, "%d channel%s remaining in broadcast on %s\n", numchans, ESS(numchans), ast_channel_name(chan));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_WHISPER)) {
|
||||
ast_audiohook_lock(&mac->whisper_audiohook);
|
||||
fres |= ast_audiohook_write_frame(&mac->whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
|
||||
ast_audiohook_unlock(&mac->whisper_audiohook);
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_BARGE)) {
|
||||
/* This hook lets us inject audio into the channel that the spyee is currently
|
||||
* bridged with. If the spyee isn't bridged with anything yet, nothing will
|
||||
* be attached and we'll need to continue attempting to attach the barge
|
||||
* audio hook.
|
||||
* The exception to this is if we are emulating barge by doing it "directly",
|
||||
* that is injecting the frames onto this channel's read queue, rather than
|
||||
* its bridged peer's write queue, then skip this. We only do one or the other. */
|
||||
if (!ast_test_flag(flags, OPTION_REVERSE_FEED) && !mac->bridge_connected && !attach_barge(mac->autochan, &mac->bridge_autochan,
|
||||
&mac->bridge_whisper_audiohook, ast_channel_name(chan), mac->name, flags)) {
|
||||
ast_debug(2, "Attached barge channel for %s\n", mac->name);
|
||||
mac->bridge_connected = 1;
|
||||
}
|
||||
|
||||
if (mac->bridge_connected) {
|
||||
ast_audiohook_lock(&mac->bridge_whisper_audiohook);
|
||||
fres |= ast_audiohook_write_frame(&mac->bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
|
||||
ast_audiohook_unlock(&mac->bridge_whisper_audiohook);
|
||||
} else if (ast_test_flag(flags, OPTION_REVERSE_FEED)) {
|
||||
/* So, this is really clever...
|
||||
* If we're connected to an n-party bridge instead of a 2-party bridge,
|
||||
* attach_barge will ALWAYS fail because we're connected to a bridge, not
|
||||
* a single peer channel.
|
||||
* Recall that the objective is for injected audio to be audible to both
|
||||
* sides of the channel. So really, the typical way of doing this by
|
||||
* directly injecting frames separately onto both channels is kind of
|
||||
* bizarre to begin with, when you think about it.
|
||||
*
|
||||
* In other words, this is how ChanSpy and this module by default work:
|
||||
* We have audio F to inject onto channels A and B, which are <= bridged =>:
|
||||
* READ <- A -> WRITE <==> READ <- B -> WRITE
|
||||
* F --^ F --^
|
||||
*
|
||||
* So that makes the same audio audible to both channels A and B, but
|
||||
* in kind of a roundabout way. What if the bridged peer changes at
|
||||
* some point, for example?
|
||||
*
|
||||
* While that method works for 2-party bridges, it doesn't work at all
|
||||
* for an n-party bridge, so we do the thing that seems obvious to begin with:
|
||||
* dump the frames onto THIS channel's read queue, and the channels will
|
||||
* make their way into the bridge like any other audio from this channel,
|
||||
* and everything just works perfectly, no matter what kind of bridging
|
||||
* scenario is being used. At that point, we don't even care if we're
|
||||
* bridged or not, and really, why should we?
|
||||
*
|
||||
* In other words, we do this:
|
||||
* READ <- A -> WRITE <==> READ <- B -> WRITE
|
||||
* F --^ F --^
|
||||
*/
|
||||
ast_audiohook_lock(&mac->whisper_audiohook);
|
||||
fres |= ast_audiohook_write_frame(&mac->whisper_audiohook, AST_AUDIOHOOK_DIRECTION_READ, f);
|
||||
ast_audiohook_unlock(&mac->whisper_audiohook);
|
||||
}
|
||||
}
|
||||
if (fres) {
|
||||
ast_log(LOG_WARNING, "Failed to write to audiohook for %s\n", mac->name);
|
||||
fres = 0;
|
||||
}
|
||||
}
|
||||
AST_RWLIST_TRAVERSE_SAFE_END;
|
||||
AST_RWLIST_UNLOCK(&chanlist);
|
||||
ast_frfree(f);
|
||||
}
|
||||
|
||||
if (!numchans) {
|
||||
ast_debug(1, "Exiting due to all target channels having left the broadcast\n");
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_SPY)) {
|
||||
ast_deactivate_generator(chan);
|
||||
} else {
|
||||
ast_channel_stop_silence_generator(chan, silgen);
|
||||
}
|
||||
|
||||
/* Cleanup any remaining targets */
|
||||
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&chanlist, mac, entry) {
|
||||
AST_RWLIST_REMOVE_CURRENT(entry);
|
||||
multi_autochan_free(mac);
|
||||
}
|
||||
AST_RWLIST_TRAVERSE_SAFE_END;
|
||||
|
||||
ast_channel_clear_flag(chan, AST_FLAG_SPYING);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int broadcast_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
struct ast_flags flags;
|
||||
struct ast_format *write_format;
|
||||
int res = -1;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(options);
|
||||
AST_APP_ARG(channels); /* Channel list last, so we can have multiple */
|
||||
);
|
||||
char *parse = NULL;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Broadcast requires at least one channel\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.channels)) {
|
||||
ast_log(LOG_WARNING, "Must specify at least one channel for broadcast\n");
|
||||
return -1;
|
||||
}
|
||||
if (args.options) {
|
||||
ast_app_parse_options(spy_opts, &flags, NULL, args.options);
|
||||
} else {
|
||||
ast_clear_flag(&flags, AST_FLAGS_ALL);
|
||||
}
|
||||
|
||||
if (!ast_test_flag(&flags, OPTION_BARGE) && !ast_test_flag(&flags, OPTION_SPY) && !ast_test_flag(&flags, OPTION_WHISPER)) {
|
||||
ast_log(LOG_WARNING, "At least one of the b, s, or w option must be specified (provided options have no effect)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_format = ao2_bump(ast_channel_writeformat(chan));
|
||||
if (ast_set_write_format(chan, ast_format_slin) < 0) {
|
||||
ast_log(LOG_ERROR, "Failed to set write format to slin.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
res = do_broadcast(chan, &flags, args.channels);
|
||||
|
||||
/* Restore previous write format */
|
||||
if (ast_set_write_format(chan, write_format)) {
|
||||
ast_log(LOG_ERROR, "Failed to restore write format for channel %s\n", ast_channel_name(chan));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
ao2_ref(write_format, -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
return ast_unregister_application(app_broadcast);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application_xml(app_broadcast, broadcast_exec);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Channel Audio Broadcasting");
|
|
@ -117,6 +117,7 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
|
|||
struct ast_str *tmp_availcause = ast_str_alloca(2048);
|
||||
struct ast_channel *tempchan;
|
||||
struct ast_custom_function *cdr_prop_func = ast_custom_function_find("CDR_PROP");
|
||||
struct ast_format_cap *caps = NULL;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(reqchans);
|
||||
AST_APP_ARG(options);
|
||||
|
@ -126,6 +127,10 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
|
|||
|
||||
AST_STANDARD_APP_ARGS(args, info);
|
||||
|
||||
ao2_lock(chan);
|
||||
caps = ao2_bump(ast_channel_nativeformats(chan));
|
||||
ao2_unlock(chan);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'a')) {
|
||||
option_all_avail = 1;
|
||||
|
@ -174,10 +179,11 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
|
|||
snprintf(trychan, sizeof(trychan), "%s/%s", tech, number);
|
||||
status = inuse = ast_device_state(trychan);
|
||||
}
|
||||
ast_str_append(&tmp_availstat, 0, "%s%d",
|
||||
ast_str_strlen(tmp_availstat) ? "&" : "", status);
|
||||
ast_str_append(&tmp_availstat, 0, "%s%d", ast_str_strlen(tmp_availstat) ? "&" : "", status);
|
||||
|
||||
if ((inuse <= (int) AST_DEVICE_NOT_INUSE)
|
||||
&& (tempchan = ast_request(tech, ast_channel_nativeformats(chan), NULL, chan, number, &status))) {
|
||||
&& (tempchan = ast_request(tech, caps, NULL, chan, number, &status))) {
|
||||
|
||||
ast_str_append(&tmp_availchan, 0, "%s%s",
|
||||
ast_str_strlen(tmp_availchan) ? "&" : "", ast_channel_name(tempchan));
|
||||
|
||||
|
@ -199,8 +205,11 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ao2_cleanup(caps);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", ast_str_buffer(tmp_availchan));
|
||||
/* Store the originally used channel too */
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", ast_str_buffer(tmp_availorig));
|
||||
|
|
|
@ -245,6 +245,11 @@
|
|||
</enum>
|
||||
</enumlist>
|
||||
</option>
|
||||
<option name="D">
|
||||
<para>Interleave the audio coming from the channel and the audio coming to the channel in
|
||||
the output audio as a dual channel stream, rather than mix it. Does nothing if 'o'
|
||||
is also set.</para>
|
||||
</option>
|
||||
<option name="e">
|
||||
<argument name="ext" required="true" />
|
||||
<para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
|
||||
|
@ -393,6 +398,7 @@ enum {
|
|||
OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
|
||||
OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
|
||||
OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
|
||||
OPTION_INTERLEAVED = (1 << 21), /* Interleave the Read and Write frames in the output frame. */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -411,6 +417,7 @@ AST_APP_OPTIONS(spy_opts, {
|
|||
AST_APP_OPTION('B', OPTION_BARGE),
|
||||
AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE),
|
||||
AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
|
||||
AST_APP_OPTION('D', OPTION_INTERLEAVED),
|
||||
AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
|
||||
AST_APP_OPTION('E', OPTION_EXITONHANGUP),
|
||||
AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
|
||||
|
@ -471,6 +478,56 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
|
|||
if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
|
||||
/* Option 'o' was set, so don't mix channel audio */
|
||||
f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, ast_format_slin);
|
||||
} else if (ast_test_flag(&csth->flags, OPTION_INTERLEAVED)) {
|
||||
/* Option 'D' was set, so mix the spy frame as an interleaved dual channel frame. */
|
||||
int i;
|
||||
struct ast_frame *fr_read = NULL;
|
||||
struct ast_frame *fr_write = NULL;
|
||||
short read_buf[samples];
|
||||
short write_buf[samples];
|
||||
short stereo_buf[samples * 2];
|
||||
struct ast_frame stereo_frame = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.datalen = sizeof(stereo_buf),
|
||||
.samples = samples,
|
||||
};
|
||||
|
||||
f = ast_audiohook_read_frame_all(&csth->spy_audiohook, samples, ast_format_slin, &fr_read, &fr_write);
|
||||
if (f) {
|
||||
ast_frame_free(f, 0);
|
||||
f = NULL;
|
||||
}
|
||||
|
||||
if (fr_read) {
|
||||
memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
|
||||
} else {
|
||||
/* silent out the output frame if we can't read the input */
|
||||
memset(read_buf, 0, sizeof(read_buf));
|
||||
}
|
||||
|
||||
if (fr_write) {
|
||||
memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
|
||||
} else {
|
||||
memset(write_buf, 0, sizeof(write_buf));
|
||||
}
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
stereo_buf[i*2] = read_buf[i];
|
||||
stereo_buf[i*2+1] = write_buf[i];
|
||||
}
|
||||
|
||||
stereo_frame.data.ptr = stereo_buf;
|
||||
stereo_frame.subclass.format = ast_format_cache_get_slin_by_rate(samples);
|
||||
|
||||
f = ast_frdup(&stereo_frame);
|
||||
|
||||
if (fr_read) {
|
||||
ast_frame_free(fr_read, 0);
|
||||
}
|
||||
if (fr_write) {
|
||||
ast_frame_free(fr_write, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, ast_format_slin);
|
||||
}
|
||||
|
|
|
@ -393,6 +393,37 @@
|
|||
ConfbridgeListRoomsComplete.</para>
|
||||
</description>
|
||||
</manager>
|
||||
<managerEvent language="en_US" name="ConfbridgeListRooms">
|
||||
<managerEventInstance class="EVENT_FLAG_REPORTING">
|
||||
<synopsis>Raised as part of the ConfbridgeListRooms action response list.</synopsis>
|
||||
<syntax>
|
||||
<parameter name="Conference">
|
||||
<para>The name of the Confbridge conference.</para>
|
||||
</parameter>
|
||||
<parameter name="Parties">
|
||||
<para>Number of users in the conference.</para>
|
||||
<para>This includes both active and waiting users.</para>
|
||||
</parameter>
|
||||
<parameter name="Marked">
|
||||
<para>Number of marked users in the conference.</para>
|
||||
</parameter>
|
||||
<parameter name="Locked">
|
||||
<para>Is the conference locked?</para>
|
||||
<enumlist>
|
||||
<enum name="Yes"/>
|
||||
<enum name="No"/>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="Muted">
|
||||
<para>Is the conference muted?</para>
|
||||
<enumlist>
|
||||
<enum name="Yes"/>
|
||||
<enum name="No"/>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
<manager name="ConfbridgeMute" language="en_US">
|
||||
<synopsis>
|
||||
Mute a Confbridge user.
|
||||
|
@ -3004,7 +3035,7 @@ static int action_playback(struct ast_bridge_channel *bridge_channel, const char
|
|||
char *file_copy = ast_strdupa(playback_file);
|
||||
char *file = NULL;
|
||||
|
||||
while ((file = strsep(&file_copy, "&"))) {
|
||||
while ((file = ast_strsep(&file_copy, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
|
||||
if (ast_stream_and_wait(bridge_channel->chan, file, "")) {
|
||||
ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
|
||||
return -1;
|
||||
|
@ -3028,7 +3059,7 @@ static int action_playback_and_continue(struct confbridge_conference *conference
|
|||
char *file_copy = ast_strdupa(playback_file);
|
||||
char *file = NULL;
|
||||
|
||||
while ((file = strsep(&file_copy, "&"))) {
|
||||
while ((file = ast_strsep(&file_copy, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
|
||||
if (ast_streamfile(bridge_channel->chan, file, ast_channel_language(bridge_channel->chan))) {
|
||||
ast_log(LOG_WARNING, "Failed to playback file %s to channel\n", file);
|
||||
return -1;
|
||||
|
@ -3991,6 +4022,7 @@ static int action_confbridgelist_item(struct mansession *s, const char *id_text,
|
|||
"MarkedUser: %s\r\n"
|
||||
"WaitMarked: %s\r\n"
|
||||
"EndMarked: %s\r\n"
|
||||
"EndMarkedAny: %s\r\n"
|
||||
"Waiting: %s\r\n"
|
||||
"Muted: %s\r\n"
|
||||
"Talking: %s\r\n"
|
||||
|
@ -4003,6 +4035,7 @@ static int action_confbridgelist_item(struct mansession *s, const char *id_text,
|
|||
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_MARKEDUSER)),
|
||||
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_WAITMARKED)),
|
||||
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_ENDMARKED)),
|
||||
AST_YESNO(ast_test_flag(&user->u_profile, USER_OPT_ENDMARKEDANY)),
|
||||
AST_YESNO(waiting),
|
||||
AST_YESNO(user->muted),
|
||||
AST_YESNO(user->talking),
|
||||
|
|
134
apps/app_dial.c
134
apps/app_dial.c
|
@ -88,9 +88,12 @@
|
|||
</argument>
|
||||
<xi:include xpointer="xpointer(/docs/info[@name='Dial_Resource'])" />
|
||||
</parameter>
|
||||
<parameter name="timeout" required="false">
|
||||
<parameter name="timeout" required="false" argsep="^">
|
||||
<para>Specifies the number of seconds we attempt to dial the specified devices.</para>
|
||||
<para>If not specified, this defaults to 136 years.</para>
|
||||
<para>If a second argument is specified, this controls the number of seconds we attempt to dial the specified devices
|
||||
without receiving early media or ringing. If neither progress, ringing, nor voice frames have been received when this
|
||||
timeout expires, the call will be treated as a CHANUNAVAIL. This can be used to skip destinations that may not be responsive.</para>
|
||||
</parameter>
|
||||
<parameter name="options" required="false">
|
||||
<optionlist>
|
||||
|
@ -242,6 +245,10 @@
|
|||
<para>Asterisk will ignore any connected line update requests or any redirecting party
|
||||
update requests it may receive on this dial attempt.</para>
|
||||
</option>
|
||||
<option name="j">
|
||||
<para>Use the initial stream topology of the caller for outgoing channels, even if the caller topology has changed.</para>
|
||||
<para>NOTE: For this option to work, it has to be present in all invocations of Dial that the caller channel goes through.</para>
|
||||
</option>
|
||||
<option name="k">
|
||||
<para>Allow the called party to enable parking of the call by sending
|
||||
the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
|
||||
|
@ -750,6 +757,7 @@ enum {
|
|||
#define OPT_RING_WITH_EARLY_MEDIA (1LLU << 43)
|
||||
#define OPT_HANGUPCAUSE (1LLU << 44)
|
||||
#define OPT_HEARPULSING (1LLU << 45)
|
||||
#define OPT_TOPOLOGY_PRESERVE (1LLU << 46)
|
||||
|
||||
enum {
|
||||
OPT_ARG_ANNOUNCE = 0,
|
||||
|
@ -795,6 +803,7 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
|
|||
AST_APP_OPTION('H', OPT_CALLER_HANGUP),
|
||||
AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
|
||||
AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
|
||||
AST_APP_OPTION('j', OPT_TOPOLOGY_PRESERVE),
|
||||
AST_APP_OPTION('k', OPT_CALLEE_PARK),
|
||||
AST_APP_OPTION('K', OPT_CALLER_PARK),
|
||||
AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
|
||||
|
@ -855,6 +864,16 @@ struct chanlist {
|
|||
|
||||
AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
|
||||
|
||||
static void topology_ds_destroy(void *data) {
|
||||
struct ast_stream_topology *top = data;
|
||||
ast_stream_topology_free(top);
|
||||
}
|
||||
|
||||
static const struct ast_datastore_info topology_ds_info = {
|
||||
.type = "app_dial_topology_preserve",
|
||||
.destroy = topology_ds_destroy,
|
||||
};
|
||||
|
||||
static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode);
|
||||
|
||||
static void chanlist_free(struct chanlist *outgoing)
|
||||
|
@ -1238,7 +1257,7 @@ static void set_duration_var(struct ast_channel *chan, const char *var_base, int
|
|||
}
|
||||
|
||||
static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
||||
struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
|
||||
struct dial_head *out_chans, int *to_answer, int *to_progress, struct ast_flags64 *peerflags,
|
||||
char *opt_args[],
|
||||
struct privacy_args *pa,
|
||||
const struct cause_args *num_in, int *result, char *dtmf_progress,
|
||||
|
@ -1251,7 +1270,9 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
{
|
||||
struct cause_args num = *num_in;
|
||||
int prestart = num.busy + num.congestion + num.nochan;
|
||||
int orig = *to;
|
||||
int orig_answer_to = *to_answer;
|
||||
int progress_to_dup = *to_progress;
|
||||
int orig_progress_to = *to_progress;
|
||||
struct ast_channel *peer = NULL;
|
||||
struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
|
||||
/* single is set if only one destination is enabled */
|
||||
|
@ -1279,7 +1300,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
* there is no point in continuing. The bridge
|
||||
* will just fail if it gets that far.
|
||||
*/
|
||||
*to = -1;
|
||||
*to_answer = -1;
|
||||
strcpy(pa->status, "CONGESTION");
|
||||
ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: can't be made compat with %s\n",
|
||||
|
@ -1295,7 +1316,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
|
||||
is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
|
||||
|
||||
while ((*to = ast_remaining_ms(start, orig)) && !peer) {
|
||||
while ((*to_answer = ast_remaining_ms(start, orig_answer_to)) && (*to_progress = ast_remaining_ms(start, progress_to_dup)) && !peer) {
|
||||
struct chanlist *o;
|
||||
int pos = 0; /* how many channels do we handle */
|
||||
int numlines = prestart;
|
||||
|
@ -1321,14 +1342,15 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
} else {
|
||||
ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
|
||||
}
|
||||
*to = 0;
|
||||
*to_answer = 0;
|
||||
if (is_cc_recall) {
|
||||
ast_cc_failed(cc_recall_core_id, "Everyone is busy/congested for the recall. How sad");
|
||||
}
|
||||
SCOPE_EXIT_RTN_VALUE(NULL, "%s: No outgoing channels available\n", ast_channel_name(in));
|
||||
}
|
||||
winner = ast_waitfor_n(watchers, pos, to);
|
||||
winner = ast_waitfor_n(watchers, pos, to_answer);
|
||||
AST_LIST_TRAVERSE(out_chans, o, node) {
|
||||
int res = 0;
|
||||
struct ast_frame *f;
|
||||
struct ast_channel *c = o->chan;
|
||||
|
||||
|
@ -1404,7 +1426,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_channel_unlock(in);
|
||||
}
|
||||
|
||||
do_forward(o, &num, peerflags, single, caller_entertained, &orig,
|
||||
do_forward(o, &num, peerflags, single, caller_entertained, &orig_answer_to,
|
||||
forced_clid, stored_clid);
|
||||
|
||||
if (o->chan) {
|
||||
|
@ -1542,6 +1564,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
* fine for ringing frames to get sent through.
|
||||
*/
|
||||
++num_ringing;
|
||||
*to_progress = -1;
|
||||
progress_to_dup = -1;
|
||||
if (ignore_cc || cc_frame_received || num_ringing == numlines) {
|
||||
ast_verb(3, "%s is ringing\n", ast_channel_name(c));
|
||||
/* Setup early media if appropriate */
|
||||
|
@ -1585,6 +1609,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_indicate(in, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
}
|
||||
*to_progress = -1;
|
||||
progress_to_dup = -1;
|
||||
if (!sent_progress) {
|
||||
struct timeval now, then;
|
||||
int64_t diff;
|
||||
|
@ -1607,7 +1633,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
"Sending MF '%s' to %s as result of "
|
||||
"receiving a PROGRESS message.\n",
|
||||
mf_progress, hearpulsing ? "parties" : "called party");
|
||||
ast_mf_stream(c, (hearpulsing ? NULL : in),
|
||||
res |= ast_mf_stream(c, (hearpulsing ? NULL : in),
|
||||
(hearpulsing ? in : NULL), mf_progress, 50, 55, 120, 65, 0);
|
||||
}
|
||||
if (!ast_strlen_zero(sf_progress)) {
|
||||
|
@ -1615,7 +1641,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
"Sending SF '%s' to %s as result of "
|
||||
"receiving a PROGRESS message.\n",
|
||||
sf_progress, (hearpulsing ? "parties" : "called party"));
|
||||
ast_sf_stream(c, (hearpulsing ? NULL : in),
|
||||
res |= ast_sf_stream(c, (hearpulsing ? NULL : in),
|
||||
(hearpulsing ? in : NULL), sf_progress, 0, 0);
|
||||
}
|
||||
if (!ast_strlen_zero(dtmf_progress)) {
|
||||
|
@ -1623,7 +1649,11 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
"Sending DTMF '%s' to the called party as result of "
|
||||
"receiving a PROGRESS message.\n",
|
||||
dtmf_progress);
|
||||
ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
|
||||
res |= ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
|
||||
}
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Called channel %s hung up post-progress before all digits could be sent\n", ast_channel_name(c));
|
||||
goto wait_over;
|
||||
}
|
||||
}
|
||||
ast_channel_publish_dial(in, c, NULL, "PROGRESS");
|
||||
|
@ -1637,7 +1667,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
"Sending MF '%s' to %s as result of "
|
||||
"receiving a WINK message.\n",
|
||||
mf_wink, (hearpulsing ? "parties" : "called party"));
|
||||
ast_mf_stream(c, (hearpulsing ? NULL : in),
|
||||
res |= ast_mf_stream(c, (hearpulsing ? NULL : in),
|
||||
(hearpulsing ? in : NULL), mf_wink, 50, 55, 120, 65, 0);
|
||||
}
|
||||
if (!ast_strlen_zero(sf_wink)) {
|
||||
|
@ -1645,9 +1675,13 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
"Sending SF '%s' to %s as result of "
|
||||
"receiving a WINK message.\n",
|
||||
sf_wink, (hearpulsing ? "parties" : "called party"));
|
||||
ast_sf_stream(c, (hearpulsing ? NULL : in),
|
||||
res |= ast_sf_stream(c, (hearpulsing ? NULL : in),
|
||||
(hearpulsing ? in : NULL), sf_wink, 0, 0);
|
||||
}
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Called channel %s hung up post-wink before all digits could be sent\n", ast_channel_name(c));
|
||||
goto wait_over;
|
||||
}
|
||||
}
|
||||
ast_indicate(in, AST_CONTROL_WINK);
|
||||
break;
|
||||
|
@ -1762,9 +1796,13 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
case AST_FRAME_VIDEO:
|
||||
case AST_FRAME_VOICE:
|
||||
case AST_FRAME_IMAGE:
|
||||
case AST_FRAME_DTMF_BEGIN:
|
||||
case AST_FRAME_DTMF_END:
|
||||
if (caller_entertained) {
|
||||
break;
|
||||
}
|
||||
*to_progress = -1;
|
||||
progress_to_dup = -1;
|
||||
/* Fall through */
|
||||
case AST_FRAME_TEXT:
|
||||
if (single && ast_write(in, f)) {
|
||||
|
@ -1793,7 +1831,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
#endif
|
||||
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
|
||||
/* Got hung up */
|
||||
*to = -1;
|
||||
*to_answer = -1;
|
||||
strcpy(pa->status, "CANCEL");
|
||||
pa->canceled = 1;
|
||||
publish_dial_end_event(in, out_chans, NULL, pa->status);
|
||||
|
@ -1817,7 +1855,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
|
||||
if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
|
||||
ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
|
||||
*to = 0;
|
||||
*to_answer = 0;
|
||||
*result = f->subclass.integer;
|
||||
strcpy(pa->status, "CANCEL");
|
||||
pa->canceled = 1;
|
||||
|
@ -1836,7 +1874,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
|
||||
detect_disconnect(in, f->subclass.integer, &featurecode)) {
|
||||
ast_verb(3, "User requested call disconnect.\n");
|
||||
*to = 0;
|
||||
*to_answer = 0;
|
||||
strcpy(pa->status, "CANCEL");
|
||||
pa->canceled = 1;
|
||||
publish_dial_end_event(in, out_chans, NULL, pa->status);
|
||||
|
@ -1947,9 +1985,15 @@ skip_frame:;
|
|||
}
|
||||
}
|
||||
|
||||
if (!*to || ast_check_hangup(in)) {
|
||||
ast_verb(3, "Nobody picked up in %d ms\n", orig);
|
||||
wait_over:
|
||||
if (!*to_answer || ast_check_hangup(in)) {
|
||||
ast_verb(3, "Nobody picked up in %d ms\n", orig_answer_to);
|
||||
publish_dial_end_event(in, out_chans, NULL, "NOANSWER");
|
||||
} else if (!*to_progress) {
|
||||
ast_verb(3, "No early media received in %d ms\n", orig_progress_to);
|
||||
publish_dial_end_event(in, out_chans, NULL, "CHANUNAVAIL");
|
||||
strcpy(pa->status, "CHANUNAVAIL");
|
||||
*to_answer = 0; /* Reset to prevent hangup */
|
||||
}
|
||||
|
||||
if (is_cc_recall) {
|
||||
|
@ -2321,7 +2365,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
struct chanlist *outgoing;
|
||||
struct chanlist *tmp;
|
||||
struct ast_channel *peer = NULL;
|
||||
int to; /* timeout */
|
||||
int to_answer, to_progress; /* timeouts */
|
||||
struct cause_args num = { chan, 0, 0, 0 };
|
||||
int cause, hanguptreecause = -1;
|
||||
|
||||
|
@ -2377,6 +2421,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
*/
|
||||
struct ast_party_caller caller;
|
||||
int max_forwards;
|
||||
struct ast_datastore *topology_ds = NULL;
|
||||
SCOPE_ENTER(1, "%s: Data: %s\n", ast_channel_name(chan), data);
|
||||
|
||||
/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
|
||||
|
@ -2678,7 +2723,21 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
*/
|
||||
ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(chan));
|
||||
|
||||
topology = ast_stream_topology_clone(ast_channel_get_stream_topology(chan));
|
||||
if (ast_test_flag64(&opts, OPT_TOPOLOGY_PRESERVE)) {
|
||||
topology_ds = ast_channel_datastore_find(chan, &topology_ds_info, NULL);
|
||||
|
||||
if (!topology_ds && (topology_ds = ast_datastore_alloc(&topology_ds_info, NULL))) {
|
||||
topology_ds->data = ast_stream_topology_clone(ast_channel_get_stream_topology(chan));
|
||||
ast_channel_datastore_add(chan, topology_ds);
|
||||
}
|
||||
}
|
||||
|
||||
if (topology_ds) {
|
||||
ao2_ref(topology_ds->data, +1);
|
||||
topology = topology_ds->data;
|
||||
} else {
|
||||
topology = ast_stream_topology_clone(ast_channel_get_stream_topology(chan));
|
||||
}
|
||||
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
|
@ -2920,14 +2979,31 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
|
||||
if (ast_strlen_zero(args.timeout)) {
|
||||
to = -1;
|
||||
to_answer = -1;
|
||||
to_progress = -1;
|
||||
} else {
|
||||
to = atoi(args.timeout);
|
||||
if (to > 0)
|
||||
to *= 1000;
|
||||
else {
|
||||
ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
|
||||
to = -1;
|
||||
char *anstimeout = strsep(&args.timeout, "^");
|
||||
if (!ast_strlen_zero(anstimeout)) {
|
||||
to_answer = atoi(anstimeout);
|
||||
if (to_answer > 0) {
|
||||
to_answer *= 1000;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Invalid answer timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
|
||||
to_answer = -1;
|
||||
}
|
||||
} else {
|
||||
to_answer = -1;
|
||||
}
|
||||
if (!ast_strlen_zero(args.timeout)) {
|
||||
to_progress = atoi(args.timeout);
|
||||
if (to_progress > 0) {
|
||||
to_progress *= 1000;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Invalid progress timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
|
||||
to_progress = -1;
|
||||
}
|
||||
} else {
|
||||
to_progress = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2967,7 +3043,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
}
|
||||
}
|
||||
|
||||
peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
|
||||
peer = wait_for_answer(chan, &out_chans, &to_answer, &to_progress, peerflags, opt_args, &pa, &num, &result,
|
||||
dtmf_progress, mf_progress, mf_wink, sf_progress, sf_wink,
|
||||
(ast_test_flag64(&opts, OPT_HEARPULSING) ? 1 : 0),
|
||||
ignore_cc, &forced_clid, &stored_clid, &config);
|
||||
|
@ -2975,7 +3051,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
if (!peer) {
|
||||
if (result) {
|
||||
res = result;
|
||||
} else if (to) { /* Musta gotten hung up */
|
||||
} else if (to_answer) { /* Musta gotten hung up */
|
||||
res = -1;
|
||||
} else { /* Nobody answered, next please? */
|
||||
res = 0;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "asterisk/say.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/adsi.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="Directory" language="en_US">
|
||||
|
@ -103,23 +104,36 @@
|
|||
receiver to their ear while entering DTMF.</para>
|
||||
<argument name="n" required="true" />
|
||||
</option>
|
||||
<option name="c">
|
||||
<para>Load the specified config file instead of voicemail.conf</para>
|
||||
<argument name="filename" required="true" />
|
||||
</option>
|
||||
<option name="s">
|
||||
<para>Skip calling the extension, instead set it in the <variable>DIRECTORY_EXTEN</variable>
|
||||
channel variable.</para>
|
||||
</option>
|
||||
<option name="d">
|
||||
<para>Enable ADSI support for screen phone searching and retrieval
|
||||
of directory results.</para>
|
||||
<para>Additionally, the channel must be ADSI-enabled and you must
|
||||
have an ADSI-compatible (Type III) CPE for this to work.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
<note><para>Only one of the <replaceable>f</replaceable>, <replaceable>l</replaceable>, or <replaceable>b</replaceable>
|
||||
options may be specified. <emphasis>If more than one is specified</emphasis>, then Directory will act as
|
||||
if <replaceable>b</replaceable> was specified. The number
|
||||
of characters for the user to type defaults to <literal>3</literal>.</para></note>
|
||||
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This application will present the calling channel with a directory of extensions from which they can search
|
||||
by name. The list of names and corresponding extensions is retrieved from the
|
||||
voicemail configuration file, <filename>voicemail.conf</filename>.</para>
|
||||
voicemail configuration file, <filename>voicemail.conf</filename>, or from the specified filename.</para>
|
||||
<para>This application will immediately exit if one of the following DTMF digits are
|
||||
received and the extension to jump to exists:</para>
|
||||
<para><literal>0</literal> - Jump to the 'o' extension, if it exists.</para>
|
||||
<para><literal>*</literal> - Jump to the 'a' extension, if it exists.</para>
|
||||
<para>This application will set the following channel variable before completion:</para>
|
||||
<para>This application will set the following channel variables before completion:</para>
|
||||
<variablelist>
|
||||
<variable name="DIRECTORY_RESULT">
|
||||
<para>Reason Directory application exited.</para>
|
||||
|
@ -131,6 +145,10 @@
|
|||
<value name="USEREXIT">User exited with '#' during selection</value>
|
||||
<value name="FAILED">The application failed</value>
|
||||
</variable>
|
||||
<variable name="DIRECTORY_EXTEN">
|
||||
<para>If the skip calling option is set this will be set to the selected extension
|
||||
provided one is selected.</para>
|
||||
</variable>
|
||||
</variablelist>
|
||||
</description>
|
||||
</application>
|
||||
|
@ -153,6 +171,9 @@ enum {
|
|||
OPT_PAUSE = (1 << 5),
|
||||
OPT_NOANSWER = (1 << 6),
|
||||
OPT_ALIAS = (1 << 7),
|
||||
OPT_CONFIG_FILE = (1 << 8),
|
||||
OPT_SKIP = (1 << 9),
|
||||
OPT_ADSI = (1 << 10),
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -160,8 +181,9 @@ enum {
|
|||
OPT_ARG_LASTNAME = 1,
|
||||
OPT_ARG_EITHER = 2,
|
||||
OPT_ARG_PAUSE = 3,
|
||||
OPT_ARG_FILENAME = 4,
|
||||
/* This *must* be the last value in this enum! */
|
||||
OPT_ARG_ARRAY_SIZE = 4,
|
||||
OPT_ARG_ARRAY_SIZE = 5,
|
||||
};
|
||||
|
||||
struct directory_item {
|
||||
|
@ -183,8 +205,74 @@ AST_APP_OPTIONS(directory_app_options, {
|
|||
AST_APP_OPTION('m', OPT_SELECTFROMMENU),
|
||||
AST_APP_OPTION('n', OPT_NOANSWER),
|
||||
AST_APP_OPTION('a', OPT_ALIAS),
|
||||
AST_APP_OPTION_ARG('c', OPT_CONFIG_FILE, OPT_ARG_FILENAME),
|
||||
AST_APP_OPTION('s', OPT_SKIP),
|
||||
AST_APP_OPTION('d', OPT_ADSI), /* (Would've used 'a', but that was taken already) */
|
||||
});
|
||||
|
||||
static int adsi_search_input(struct ast_channel *chan)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
int bytes = 0;
|
||||
unsigned char keys[6];
|
||||
|
||||
memset(keys, 0, sizeof(keys));
|
||||
|
||||
bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
|
||||
bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
|
||||
bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
|
||||
bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Query: ***", "");
|
||||
bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
|
||||
bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Search", "Search", "#", 1);
|
||||
bytes += ast_adsi_set_keys(buf + bytes, keys);
|
||||
bytes += ast_adsi_voice_mode(buf + bytes, 0);
|
||||
|
||||
ast_debug(3, "Sending ADSI search input screen on %s\n", ast_channel_name(chan));
|
||||
|
||||
return ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
|
||||
}
|
||||
|
||||
static int adsi_confirm_match(struct ast_channel *chan, int seq, int total, const char *exten, const char *name, int showexten)
|
||||
{
|
||||
unsigned char buf[4096];
|
||||
int alignments[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
|
||||
char *lines[5] = {NULL, NULL, NULL, NULL, NULL};
|
||||
int x, bytes = 0;
|
||||
unsigned char keys[8];
|
||||
char matchbuf[32];
|
||||
|
||||
snprintf(matchbuf, sizeof(matchbuf), "%d of %d", seq + 1, total); /* Make it 1-indexed for user consumption */
|
||||
|
||||
lines[0] = " "; /* Leave the first line empty so the following lines stand out more */
|
||||
lines[1] = matchbuf;
|
||||
lines[2] = (char*) name;
|
||||
|
||||
if (showexten) {
|
||||
/* If say extension option is set, show it for ADSI as well */
|
||||
lines[3] = (char*) exten;
|
||||
}
|
||||
|
||||
/* Don't use ast_adsi_print here, this way we can send it all at once instead of in 2 transmissions */
|
||||
for (x = 0; lines[x]; x++) {
|
||||
bytes += ast_adsi_display(buf + bytes, ADSI_INFO_PAGE, x + 1, alignments[x], 0, lines[x], "");
|
||||
}
|
||||
bytes += ast_adsi_set_line(buf + bytes, ADSI_INFO_PAGE, 1);
|
||||
|
||||
keys[3] = ADSI_KEY_APPS + 3;
|
||||
keys[4] = ADSI_KEY_APPS + 4;
|
||||
keys[5] = ADSI_KEY_APPS + 5;
|
||||
/* You might think we only need to set the keys up the first time, but nope, we've got to do it each time. */
|
||||
bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Dial", "Dial", "1", 0);
|
||||
bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Next", "Next", "*", 0);
|
||||
bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 0);
|
||||
bytes += ast_adsi_set_keys(buf + bytes, keys);
|
||||
bytes += ast_adsi_voice_mode(buf + bytes, 0);
|
||||
|
||||
ast_debug(3, "Sending ADSI confirmation menu for %s\n", name);
|
||||
|
||||
return ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
|
||||
}
|
||||
|
||||
static int compare(const char *text, const char *template)
|
||||
{
|
||||
char digit;
|
||||
|
@ -318,6 +406,9 @@ static int select_entry(struct ast_channel *chan, const char *dialcontext, const
|
|||
if (ast_test_flag(flags, OPT_FROMVOICEMAIL)) {
|
||||
/* We still want to set the exten though */
|
||||
ast_channel_exten_set(chan, item->exten);
|
||||
} else if (ast_test_flag(flags, OPT_SKIP)) {
|
||||
/* Skip calling the extension, only set it in the channel variable. */
|
||||
pbx_builtin_setvar_helper(chan, "DIRECTORY_EXTEN", item->exten);
|
||||
} else if (ast_goto_if_exists(chan, S_OR(dialcontext, item->context), item->exten, 1)) {
|
||||
ast_log(LOG_WARNING,
|
||||
"Can't find extension '%s' in context '%s'. "
|
||||
|
@ -356,6 +447,10 @@ static int select_item_seq(struct ast_channel *chan, struct directory_item **ite
|
|||
for (ptr = items, i = 0; i < count; i++, ptr++) {
|
||||
item = *ptr;
|
||||
|
||||
if (ast_test_flag(flags, OPT_ADSI) && adsi_confirm_match(chan, i, count, item->exten, item->name, ast_test_flag(flags, OPT_SAYEXTENSION))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (loop = 3 ; loop > 0; loop--) {
|
||||
if (!res)
|
||||
res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags);
|
||||
|
@ -458,7 +553,7 @@ static int select_item_menu(struct ast_channel *chan, struct directory_item **it
|
|||
|
||||
AST_THREADSTORAGE(commonbuf);
|
||||
|
||||
static struct ast_config *realtime_directory(char *context)
|
||||
static struct ast_config *realtime_directory(char *context, const char *filename)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
struct ast_config *rtdata = NULL;
|
||||
|
@ -475,14 +570,14 @@ static struct ast_config *realtime_directory(char *context)
|
|||
}
|
||||
|
||||
/* Load flat file config. */
|
||||
cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
|
||||
cfg = ast_config_load(filename, config_flags);
|
||||
|
||||
if (!cfg) {
|
||||
/* Loading config failed. */
|
||||
ast_log(LOG_WARNING, "Loading config failed.\n");
|
||||
return NULL;
|
||||
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
|
||||
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", VOICEMAIL_CONFIG);
|
||||
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -867,7 +962,9 @@ static int directory_exec(struct ast_channel *chan, const char *data)
|
|||
if (args.options && ast_app_parse_options(directory_app_options, &flags, opts, args.options))
|
||||
return -1;
|
||||
|
||||
if (!(cfg = realtime_directory(args.vmcontext))) {
|
||||
cfg = realtime_directory(args.vmcontext, S_OR(opts[OPT_ARG_FILENAME], VOICEMAIL_CONFIG));
|
||||
|
||||
if (!cfg) {
|
||||
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -913,6 +1010,18 @@ static int directory_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
digits[7] = digit + '0';
|
||||
|
||||
if (ast_test_flag(&flags, OPT_ADSI)) {
|
||||
if (!ast_adsi_available(chan)) {
|
||||
ast_log(LOG_WARNING, "ADSI not available on %s\n", ast_channel_name(chan));
|
||||
ast_clear_flag(&flags, OPT_ADSI);
|
||||
} else {
|
||||
res = ast_adsi_load_session(chan, NULL, 0, 1);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_channel_state(chan) != AST_STATE_UP) {
|
||||
if (!ast_test_flag(&flags, OPT_NOANSWER)) {
|
||||
/* Otherwise answer unless we're supposed to read while on-hook */
|
||||
|
@ -920,6 +1029,9 @@ static int directory_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (ast_test_flag(&flags, OPT_ADSI) && adsi_search_input(chan)) {
|
||||
return -1;
|
||||
}
|
||||
if (!ast_strlen_zero(dirintro) && !res) {
|
||||
res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY);
|
||||
} else if (!res) {
|
||||
|
|
|
@ -836,8 +836,9 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ast_verb(3, "Skip playback of caller name / norecording\n");
|
||||
tmpuser->state = 2;
|
||||
ast_debug(1, "Taking call with no prompt\n");
|
||||
ast_frfree(f);
|
||||
return tmpuser->ochan;
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_BUSY:
|
||||
|
@ -964,11 +965,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!tpargs->enable_callee_prompt && tmpuser) {
|
||||
ast_debug(1, "Taking call with no prompt\n");
|
||||
ast_frfree(f);
|
||||
return tmpuser->ochan;
|
||||
}
|
||||
if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
|
||||
int cmp_len;
|
||||
|
||||
|
@ -1072,6 +1068,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
|
|||
ast_copy_string(num, nm->number, sizeof(num));
|
||||
for (number = num; number; number = rest) {
|
||||
struct ast_channel *outbound;
|
||||
struct ast_format_cap *caps;
|
||||
|
||||
rest = strchr(number, '&');
|
||||
if (rest) {
|
||||
|
@ -1101,8 +1098,15 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
|
|||
? "/n" : "/m");
|
||||
}
|
||||
|
||||
outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller,
|
||||
tmpuser->dialarg, &dg);
|
||||
/* Capture nativeformats reference in case it gets changed */
|
||||
ast_channel_lock(caller);
|
||||
caps = ao2_bump(ast_channel_nativeformats(caller));
|
||||
ast_channel_unlock(caller);
|
||||
|
||||
outbound = ast_request("Local", caps, NULL, caller, tmpuser->dialarg, &dg);
|
||||
|
||||
ao2_cleanup(caps);
|
||||
|
||||
if (!outbound) {
|
||||
ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
|
||||
tmpuser->dialarg, ast_cause2str(dg));
|
||||
|
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright 2022, Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief If Branch Implementation
|
||||
*
|
||||
* \author Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>extended</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/channel.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="If" language="en_US">
|
||||
<synopsis>
|
||||
Start an if branch.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="expr" required="true" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Start an If branch. Execution will continue inside the branch
|
||||
if expr is true.</para>
|
||||
<note><para>This application (and related applications) set variables
|
||||
internally during execution.</para></note>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">ElseIf</ref>
|
||||
<ref type="application">Else</ref>
|
||||
<ref type="application">EndIf</ref>
|
||||
<ref type="application">ExitIf</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="ElseIf" language="en_US">
|
||||
<synopsis>
|
||||
Start an else if branch.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="expr" required="true" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Start an optional ElseIf branch. Execution will continue inside the branch
|
||||
if expr is true and if previous If and ElseIf branches evaluated to false.</para>
|
||||
<para>Please note that execution inside a true If branch will fallthrough into
|
||||
ElseIf unless the If segment is terminated with an ExitIf call. This is only
|
||||
necessary with ElseIf but not with Else.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">If</ref>
|
||||
<ref type="application">Else</ref>
|
||||
<ref type="application">EndIf</ref>
|
||||
<ref type="application">ExitIf</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="Else" language="en_US">
|
||||
<synopsis>
|
||||
Define an optional else branch.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="expr" required="true" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Start an Else branch. Execution will jump here if all previous
|
||||
If and ElseIf branches evaluated to false.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">If</ref>
|
||||
<ref type="application">ElseIf</ref>
|
||||
<ref type="application">EndIf</ref>
|
||||
<ref type="application">ExitIf</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="EndIf" language="en_US">
|
||||
<synopsis>
|
||||
End an if branch.
|
||||
</synopsis>
|
||||
<syntax />
|
||||
<description>
|
||||
<para>Ends the branch begun by the preceding <literal>If()</literal> application.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">If</ref>
|
||||
<ref type="application">ElseIf</ref>
|
||||
<ref type="application">Else</ref>
|
||||
<ref type="application">ExitIf</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="ExitIf" language="en_US">
|
||||
<synopsis>
|
||||
End an If branch.
|
||||
</synopsis>
|
||||
<syntax />
|
||||
<description>
|
||||
<para>Exits an <literal>If()</literal> branch, whether or not it has completed.</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">If</ref>
|
||||
<ref type="application">ElseIf</ref>
|
||||
<ref type="application">Else</ref>
|
||||
<ref type="application">EndIf</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static char *if_app = "If";
|
||||
static char *elseif_app = "ElseIf";
|
||||
static char *else_app = "Else";
|
||||
static char *stop_app = "EndIf";
|
||||
static char *exit_app = "ExitIf";
|
||||
|
||||
#define VAR_SIZE 64
|
||||
|
||||
static const char *get_index(struct ast_channel *chan, const char *prefix, int idx)
|
||||
{
|
||||
char varname[VAR_SIZE];
|
||||
|
||||
snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);
|
||||
return pbx_builtin_getvar_helper(chan, varname);
|
||||
}
|
||||
|
||||
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
|
||||
{
|
||||
struct ast_exten *e;
|
||||
struct ast_context *c2;
|
||||
int idx;
|
||||
|
||||
for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
|
||||
if (ast_extension_match(ast_get_extension_name(e), exten)) {
|
||||
int needmatch = ast_get_extension_matchcid(e);
|
||||
if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
|
||||
(!needmatch)) {
|
||||
/* This is the matching extension we want */
|
||||
struct ast_exten *p;
|
||||
for (p = ast_walk_extension_priorities(e, NULL); p; p = ast_walk_extension_priorities(e, p)) {
|
||||
if (priority != ast_get_extension_priority(p))
|
||||
continue;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match; run through includes */
|
||||
for (idx = 0; idx < ast_context_includes_count(c); idx++) {
|
||||
const struct ast_include *i = ast_context_includes_get(c, idx);
|
||||
|
||||
for (c2 = ast_walk_contexts(NULL); c2; c2 = ast_walk_contexts(c2)) {
|
||||
if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
|
||||
e = find_matching_priority(c2, exten, priority, callerid);
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int find_matching_endif(struct ast_channel *chan, const char *otherapp)
|
||||
{
|
||||
struct ast_context *c;
|
||||
int res = -1;
|
||||
|
||||
if (ast_rdlock_contexts()) {
|
||||
ast_log(LOG_ERROR, "Failed to lock contexts list\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (c = ast_walk_contexts(NULL); c; c = ast_walk_contexts(c)) {
|
||||
struct ast_exten *e;
|
||||
|
||||
if (!ast_rdlock_context(c)) {
|
||||
if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
|
||||
/* This is the matching context we want */
|
||||
|
||||
int cur_priority = ast_channel_priority(chan) + 1, level = 1;
|
||||
|
||||
for (e = find_matching_priority(c, ast_channel_exten(chan), cur_priority,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
|
||||
e;
|
||||
e = find_matching_priority(c, ast_channel_exten(chan), ++cur_priority,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
|
||||
if (!strcasecmp(ast_get_extension_app(e), "IF")) {
|
||||
level++;
|
||||
} else if (!strcasecmp(ast_get_extension_app(e), "ENDIF")) {
|
||||
level--;
|
||||
}
|
||||
|
||||
if (!otherapp && level == 0) {
|
||||
res = cur_priority;
|
||||
break;
|
||||
} else if (otherapp && level == 1 && !strcasecmp(ast_get_extension_app(e), otherapp)) {
|
||||
res = cur_priority;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_unlock_context(c);
|
||||
if (res > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_unlock_contexts();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int if_helper(struct ast_channel *chan, const char *data, int end)
|
||||
{
|
||||
int res = 0;
|
||||
const char *if_pri = NULL;
|
||||
char *my_name = NULL;
|
||||
const char *label = NULL;
|
||||
char varname[VAR_SIZE + 3]; /* + IF_ */
|
||||
char end_varname[sizeof(varname) + 4]; /* + END_ + sizeof(varname) */
|
||||
const char *prefix = "IF";
|
||||
size_t size = 0;
|
||||
int used_index_i = -1, x = 0;
|
||||
char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";
|
||||
|
||||
if (!chan) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (x = 0 ;; x++) {
|
||||
if (get_index(chan, prefix, x)) {
|
||||
used_index_i = x;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(used_index, sizeof(used_index), "%d", used_index_i);
|
||||
snprintf(new_index, sizeof(new_index), "%d", used_index_i + 1);
|
||||
|
||||
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
|
||||
my_name = ast_alloca(size);
|
||||
memset(my_name, 0, size);
|
||||
snprintf(my_name, size, "%s_%s_%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (end > 1) {
|
||||
label = used_index;
|
||||
} else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {
|
||||
label = new_index;
|
||||
pbx_builtin_setvar_helper(chan, my_name, label);
|
||||
}
|
||||
snprintf(varname, sizeof(varname), "%s_%s", prefix, label);
|
||||
if ((if_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {
|
||||
if_pri = ast_strdupa(if_pri);
|
||||
snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if ((end <= 1 && !pbx_checkcondition(ast_strdupa(data))) || (end > 1)) {
|
||||
/* Condition Met (clean up helper vars) */
|
||||
const char *goto_str;
|
||||
int pri, endifpri;
|
||||
pbx_builtin_setvar_helper(chan, varname, NULL);
|
||||
pbx_builtin_setvar_helper(chan, my_name, NULL);
|
||||
snprintf(end_varname,sizeof(end_varname),"END_%s",varname);
|
||||
ast_channel_lock(chan);
|
||||
/* For EndIf, simply go to the next priority.
|
||||
* We do not add 1 to ast_channel_priority because the dialplan will
|
||||
* auto-increment the priority when we return, so just keep the priority as is.
|
||||
* For ExitIf or false If() condition, we need to find the end of the current
|
||||
* If branch (at same indentation) and branch there. */
|
||||
endifpri = end == 2 ? ast_channel_priority(chan) : find_matching_endif(chan, NULL);
|
||||
if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {
|
||||
ast_parseable_goto(chan, goto_str);
|
||||
pbx_builtin_setvar_helper(chan, end_varname, NULL);
|
||||
} else if (end <= 1 && (pri = find_matching_endif(chan, "ElseIf")) > 0 && pri < endifpri) {
|
||||
pri--; /* back up a priority, since it returned the priority after the ElseIf */
|
||||
/* If is false, and ElseIf exists, so jump to ElseIf */
|
||||
ast_verb(3, "Taking conditional false branch, jumping to priority %d\n", pri);
|
||||
ast_channel_priority_set(chan, pri);
|
||||
} else if (end <= 1 && (pri = find_matching_endif(chan, "Else")) > 0 && pri < endifpri) {
|
||||
/* don't need to back up a priority, because we don't actually need to execute Else, just jump to the priority after. Directly executing Else will exit the conditional. */
|
||||
/* If is false, and Else exists, so jump to Else */
|
||||
ast_verb(3, "Taking absolute false branch, jumping to priority %d\n", pri);
|
||||
ast_channel_priority_set(chan, pri);
|
||||
} else {
|
||||
pri = endifpri;
|
||||
if (pri > 0) {
|
||||
ast_verb(3, "Exiting conditional, jumping to priority %d\n", pri);
|
||||
ast_channel_priority_set(chan, pri);
|
||||
} else if (end == 4) { /* Condition added because of end > 0 instead of end == 4 */
|
||||
ast_log(LOG_WARNING, "Couldn't find matching EndIf? (If at %s@%s priority %d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
|
||||
}
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (end <= 1 && !if_pri) {
|
||||
char *goto_str;
|
||||
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
|
||||
goto_str = ast_alloca(size);
|
||||
memset(goto_str, 0, size);
|
||||
snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));
|
||||
pbx_builtin_setvar_helper(chan, varname, goto_str);
|
||||
} else if (end > 1 && if_pri) {
|
||||
/* END of branch */
|
||||
snprintf(end_varname, sizeof(end_varname), "END_%s", varname);
|
||||
if (!pbx_builtin_getvar_helper(chan, end_varname)) {
|
||||
char *goto_str;
|
||||
size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;
|
||||
goto_str = ast_alloca(size);
|
||||
memset(goto_str, 0, size);
|
||||
snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)+1);
|
||||
pbx_builtin_setvar_helper(chan, end_varname, goto_str);
|
||||
}
|
||||
ast_parseable_goto(chan, if_pri);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int if_exec(struct ast_channel *chan, const char *data) {
|
||||
return if_helper(chan, data, 0);
|
||||
}
|
||||
|
||||
static int elseif_exec(struct ast_channel *chan, const char *data) {
|
||||
return if_helper(chan, data, 1);
|
||||
}
|
||||
|
||||
static int end_exec(struct ast_channel *chan, const char *data) {
|
||||
return if_helper(chan, data, 2);
|
||||
}
|
||||
|
||||
static int else_exec(struct ast_channel *chan, const char *data) {
|
||||
return if_helper(chan, data, 3);
|
||||
}
|
||||
|
||||
static int exit_exec(struct ast_channel *chan, const char *data) {
|
||||
return if_helper(chan, data, 4);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(if_app);
|
||||
res |= ast_unregister_application(elseif_app);
|
||||
res |= ast_unregister_application(stop_app);
|
||||
res |= ast_unregister_application(else_app);
|
||||
res |= ast_unregister_application(exit_app);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application_xml(if_app, if_exec);
|
||||
res |= ast_register_application_xml(elseif_app, elseif_exec);
|
||||
res |= ast_register_application_xml(stop_app, end_exec);
|
||||
res |= ast_register_application_xml(else_app, else_exec);
|
||||
res |= ast_register_application_xml(exit_app, exit_exec);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "If Branch and Conditional Execution");
|
|
@ -262,7 +262,7 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
|
|||
char *save_macro_priority;
|
||||
char *save_macro_offset;
|
||||
int save_in_subroutine;
|
||||
struct ast_datastore *macro_store = ast_channel_datastore_find(chan, ¯o_ds_info, NULL);
|
||||
struct ast_datastore *macro_store;
|
||||
int had_infinite_include_error = 0;
|
||||
static int deprecation_notice = 0;
|
||||
|
||||
|
@ -277,6 +277,10 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
|
|||
ast_log(LOG_WARNING, "Dialplan should be updated to use Gosub instead.\n");
|
||||
}
|
||||
|
||||
ast_channel_lock(chan);
|
||||
|
||||
macro_store = ast_channel_datastore_find(chan, ¯o_ds_info, NULL);
|
||||
|
||||
do {
|
||||
if (macro_store) {
|
||||
break;
|
||||
|
@ -291,7 +295,6 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
|
|||
} while (0);
|
||||
|
||||
/* does the user want a deeper rabbit hole? */
|
||||
ast_channel_lock(chan);
|
||||
if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
|
||||
sscanf(s, "%30d", &maxdepth);
|
||||
}
|
||||
|
|
|
@ -639,6 +639,82 @@
|
|||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
<managerEvent language="en_US" name="MeetmeList">
|
||||
<managerEventInstance class="EVENT_FLAG_CALL">
|
||||
<synopsis>Raised in response to a MeetmeList command.</synopsis>
|
||||
<syntax>
|
||||
<parameter name="Conference">
|
||||
<para>Conference ID.</para>
|
||||
</parameter>
|
||||
<parameter name="UserNumber">
|
||||
<para>User ID.</para>
|
||||
</parameter>
|
||||
<parameter name="CallerIDNum">
|
||||
<para>Caller ID number.</para>
|
||||
</parameter>
|
||||
<parameter name="CallerIDName">
|
||||
<para>Caller ID name.</para>
|
||||
</parameter>
|
||||
<parameter name="ConnectedLineNum">
|
||||
<para>Connected Line number.</para>
|
||||
</parameter>
|
||||
<parameter name="ConnectedLineName">
|
||||
<para>Connected Line name.</para>
|
||||
</parameter>
|
||||
<parameter name="Channel">
|
||||
<para>Channel name</para>
|
||||
</parameter>
|
||||
<parameter name="Admin">
|
||||
<para>Whether or not the user is an admin.</para>
|
||||
</parameter>
|
||||
<parameter name="Role">
|
||||
<para>User role. Can be "Listen only", "Talk only", or "Talk and listen".</para>
|
||||
</parameter>
|
||||
<parameter name="MarkedUser">
|
||||
<para>Whether or not the user is a marked user.</para>
|
||||
</parameter>
|
||||
<parameter name="Muted">
|
||||
<para>Whether or not the user is currently muted.</para>
|
||||
</parameter>
|
||||
<parameter name="Talking">
|
||||
<para>Whether or not the user is currently talking.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<see-also>
|
||||
<ref type="manager">MeetmeList</ref>
|
||||
<ref type="application">MeetMe</ref>
|
||||
</see-also>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
<managerEvent language="en_US" name="MeetmeListRooms">
|
||||
<managerEventInstance class="EVENT_FLAG_CALL">
|
||||
<synopsis>Raised in response to a MeetmeListRooms command.</synopsis>
|
||||
<syntax>
|
||||
<parameter name="Conference">
|
||||
<para>Conference ID.</para>
|
||||
</parameter>
|
||||
<parameter name="Parties">
|
||||
<para>Number of parties in the conference.</para>
|
||||
</parameter>
|
||||
<parameter name="Marked">
|
||||
<para>Number of marked users in the conference.</para>
|
||||
</parameter>
|
||||
<parameter name="Activity">
|
||||
<para>Total duration of conference in HH:MM:SS format.</para>
|
||||
</parameter>
|
||||
<parameter name="Creation">
|
||||
<para>How the conference was created: "Dyanmic" or "Static".</para>
|
||||
</parameter>
|
||||
<parameter name="Locked">
|
||||
<para>Whether or not the conference is locked.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<see-also>
|
||||
<ref type="manager">MeetmeListRooms</ref>
|
||||
<ref type="application">MeetMe</ref>
|
||||
</see-also>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
***/
|
||||
|
||||
#define CONFIG_FILE_NAME "meetme.conf"
|
||||
|
@ -6073,7 +6149,7 @@ struct run_station_args {
|
|||
|
||||
static void answer_trunk_chan(struct ast_channel *chan)
|
||||
{
|
||||
ast_answer(chan);
|
||||
ast_raw_answer(chan);
|
||||
ast_indicate(chan, -1);
|
||||
}
|
||||
|
||||
|
@ -6918,8 +6994,18 @@ static void *dial_trunk(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
/* Wait for dial to end, while servicing the channel */
|
||||
while (ast_waitfor(trunk_ref->chan, 100)) {
|
||||
unsigned int done = 0;
|
||||
struct ast_frame *fr = ast_read(trunk_ref->chan);
|
||||
|
||||
if (!fr) {
|
||||
ast_debug(1, "Channel %s did not return a frame, must have hung up\n", ast_channel_name(trunk_ref->chan));
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
ast_frfree(fr); /* Ignore while dialing */
|
||||
|
||||
switch ((dial_res = ast_dial_state(dial))) {
|
||||
case AST_DIAL_RESULT_ANSWERED:
|
||||
trunk_ref->trunk->chan = ast_dial_answered(dial);
|
||||
|
@ -6956,8 +7042,6 @@ static void *dial_trunk(void *data)
|
|||
last_state = current_state;
|
||||
}
|
||||
|
||||
/* avoid tight loop... sleep for 1/10th second */
|
||||
ast_safe_sleep(trunk_ref->chan, 100);
|
||||
}
|
||||
|
||||
if (!trunk_ref->trunk->chan) {
|
||||
|
@ -7116,8 +7200,10 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
|
|||
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL);
|
||||
/* Create a thread to dial the trunk and dump it into the conference.
|
||||
* However, we want to wait until the trunk has been dialed and the
|
||||
* conference is created before continuing on here. */
|
||||
ast_autoservice_start(chan);
|
||||
* conference is created before continuing on here.
|
||||
* Don't autoservice the channel or we'll have multiple threads
|
||||
* handling it. dial_trunk services the channel.
|
||||
*/
|
||||
ast_mutex_init(&cond_lock);
|
||||
ast_cond_init(&cond, NULL);
|
||||
ast_mutex_lock(&cond_lock);
|
||||
|
@ -7126,7 +7212,7 @@ static int sla_station_exec(struct ast_channel *chan, const char *data)
|
|||
ast_mutex_unlock(&cond_lock);
|
||||
ast_mutex_destroy(&cond_lock);
|
||||
ast_cond_destroy(&cond);
|
||||
ast_autoservice_stop(chan);
|
||||
|
||||
if (!trunk_ref->trunk->chan) {
|
||||
ast_debug(1, "Trunk didn't get created. chan: %lx\n", (unsigned long) trunk_ref->trunk->chan);
|
||||
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
|
||||
|
|
|
@ -235,6 +235,7 @@ static const char sendmf_name[] = "SendMF";
|
|||
* \param buflen Size of buffer
|
||||
* \param timeout ms to wait for all digits before giving up
|
||||
* \param features Any additional DSP features to use
|
||||
* \param laxkp Receive digits even if KP not received
|
||||
* \param override Start over if we receive additional KPs
|
||||
* \param no_kp Don't include KP in the output
|
||||
* \param no_st Don't include start digits in the output
|
||||
|
|
|
@ -90,6 +90,16 @@
|
|||
<para>Play a periodic beep while this call is being recorded.</para>
|
||||
<argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
|
||||
</option>
|
||||
<option name="c">
|
||||
<para>Use the real Caller ID from the channel for the voicemail Caller ID.</para>
|
||||
<para>By default, the Connected Line is used. If you want the channel caller's
|
||||
real number, you may need to specify this option.</para>
|
||||
</option>
|
||||
<option name="d">
|
||||
<para>Delete the recording file as soon as MixMonitor is done with it.</para>
|
||||
<para>For example, if you use the m option to dispatch the recording to a voicemail box,
|
||||
you can specify this option to delete the original copy of it afterwards.</para>
|
||||
</option>
|
||||
<option name="v">
|
||||
<para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
|
||||
(range <literal>-4</literal> to <literal>4</literal>)</para>
|
||||
|
@ -407,6 +417,8 @@ enum mixmonitor_flags {
|
|||
MUXFLAG_BEEP_STOP = (1 << 13),
|
||||
MUXFLAG_DEPRECATED_RWSYNC = (1 << 14),
|
||||
MUXFLAG_NO_RWSYNC = (1 << 15),
|
||||
MUXFLAG_AUTO_DELETE = (1 << 16),
|
||||
MUXFLAG_REAL_CALLERID = (1 << 17),
|
||||
};
|
||||
|
||||
enum mixmonitor_args {
|
||||
|
@ -427,6 +439,8 @@ AST_APP_OPTIONS(mixmonitor_opts, {
|
|||
AST_APP_OPTION('a', MUXFLAG_APPEND),
|
||||
AST_APP_OPTION('b', MUXFLAG_BRIDGED),
|
||||
AST_APP_OPTION_ARG('B', MUXFLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
|
||||
AST_APP_OPTION('c', MUXFLAG_REAL_CALLERID),
|
||||
AST_APP_OPTION('d', MUXFLAG_AUTO_DELETE),
|
||||
AST_APP_OPTION('p', MUXFLAG_BEEP_START),
|
||||
AST_APP_OPTION('P', MUXFLAG_BEEP_STOP),
|
||||
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
|
||||
|
@ -860,6 +874,19 @@ static void *mixmonitor_thread(void *obj)
|
|||
ast_debug(3, "No recipients to forward monitor to, moving on.\n");
|
||||
}
|
||||
|
||||
if (ast_test_flag(mixmonitor, MUXFLAG_AUTO_DELETE)) {
|
||||
ast_debug(3, "Deleting our copies of recording files\n");
|
||||
if (!ast_strlen_zero(fs_ext)) {
|
||||
ast_filedelete(mixmonitor->filename, fs_ext);
|
||||
}
|
||||
if (!ast_strlen_zero(fs_read_ext)) {
|
||||
ast_filedelete(mixmonitor->filename_read, fs_ext);
|
||||
}
|
||||
if (!ast_strlen_zero(fs_write_ext)) {
|
||||
ast_filedelete(mixmonitor->filename_write, fs_ext);
|
||||
}
|
||||
}
|
||||
|
||||
mixmonitor_free(mixmonitor);
|
||||
|
||||
ast_module_unref(ast_module_info->self);
|
||||
|
@ -1015,20 +1042,37 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
|
|||
|
||||
if (!ast_strlen_zero(recipients)) {
|
||||
char callerid[256];
|
||||
struct ast_party_connected_line *connected;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
|
||||
/* We use the connected line of the invoking channel for caller ID. */
|
||||
/* We use the connected line of the invoking channel for caller ID,
|
||||
* unless we've been told to use the Caller ID.
|
||||
* The initial use for this relied on Connected Line to get the
|
||||
* actual number for recording with Digium phones,
|
||||
* but in generic use the Caller ID is likely what people want.
|
||||
*/
|
||||
|
||||
connected = ast_channel_connected(chan);
|
||||
ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
|
||||
connected->id.name.str, connected->id.number.valid,
|
||||
connected->id.number.str);
|
||||
ast_callerid_merge(callerid, sizeof(callerid),
|
||||
S_COR(connected->id.name.valid, connected->id.name.str, NULL),
|
||||
S_COR(connected->id.number.valid, connected->id.number.str, NULL),
|
||||
"Unknown");
|
||||
if (ast_test_flag(mixmonitor, MUXFLAG_REAL_CALLERID)) {
|
||||
struct ast_party_caller *caller;
|
||||
caller = ast_channel_caller(chan);
|
||||
ast_debug(3, "Caller ID = %d - %s : %d - %s\n", caller->id.name.valid,
|
||||
caller->id.name.str, caller->id.number.valid,
|
||||
caller->id.number.str);
|
||||
ast_callerid_merge(callerid, sizeof(callerid),
|
||||
S_COR(caller->id.name.valid, caller->id.name.str, NULL),
|
||||
S_COR(caller->id.number.valid, caller->id.number.str, NULL),
|
||||
"Unknown");
|
||||
} else {
|
||||
struct ast_party_connected_line *connected;
|
||||
connected = ast_channel_connected(chan);
|
||||
ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
|
||||
connected->id.name.str, connected->id.number.valid,
|
||||
connected->id.number.str);
|
||||
ast_callerid_merge(callerid, sizeof(callerid),
|
||||
S_COR(connected->id.name.valid, connected->id.name.str, NULL),
|
||||
S_COR(connected->id.number.valid, connected->id.number.str, NULL),
|
||||
"Unknown");
|
||||
}
|
||||
|
||||
ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
|
||||
ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
|
||||
|
@ -1403,6 +1447,50 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
/*! \brief Mute / unmute an individual MixMonitor by id */
|
||||
static int mute_mixmonitor_instance(struct ast_channel *chan, const char *data,
|
||||
enum ast_audiohook_flags flag, int clearmute)
|
||||
{
|
||||
struct ast_datastore *datastore = NULL;
|
||||
char *parse = "";
|
||||
struct mixmonitor_ds *mixmonitor_ds;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(mixmonid);
|
||||
);
|
||||
|
||||
if (!ast_strlen_zero(data)) {
|
||||
parse = ast_strdupa(data);
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
ast_channel_lock(chan);
|
||||
|
||||
datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info,
|
||||
S_OR(args.mixmonid, NULL));
|
||||
if (!datastore) {
|
||||
ast_channel_unlock(chan);
|
||||
return -1;
|
||||
}
|
||||
mixmonitor_ds = datastore->data;
|
||||
|
||||
ast_mutex_lock(&mixmonitor_ds->lock);
|
||||
|
||||
if (mixmonitor_ds->audiohook) {
|
||||
if (clearmute) {
|
||||
ast_clear_flag(mixmonitor_ds->audiohook, flag);
|
||||
} else {
|
||||
ast_set_flag(mixmonitor_ds->audiohook, flag);
|
||||
}
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&mixmonitor_ds->lock);
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Mute / unmute a MixMonitor channel */
|
||||
static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
|
||||
{
|
||||
|
@ -1411,7 +1499,8 @@ static int manager_mute_mixmonitor(struct mansession *s, const struct message *m
|
|||
const char *id = astman_get_header(m, "ActionID");
|
||||
const char *state = astman_get_header(m, "State");
|
||||
const char *direction = astman_get_header(m,"Direction");
|
||||
int clearmute = 1;
|
||||
const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
|
||||
int clearmute = 1, mutedcount = 0;
|
||||
enum ast_audiohook_flags flag;
|
||||
RAII_VAR(struct stasis_message *, stasis_message, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, stasis_message_blob, NULL, ast_json_unref);
|
||||
|
@ -1450,15 +1539,28 @@ static int manager_mute_mixmonitor(struct mansession *s, const struct message *m
|
|||
return AMI_SUCCESS;
|
||||
}
|
||||
|
||||
if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
|
||||
ast_channel_unref(c);
|
||||
astman_send_error(s, m, "Cannot set mute flag");
|
||||
return AMI_SUCCESS;
|
||||
if (ast_strlen_zero(mixmonitor_id)) {
|
||||
mutedcount = ast_audiohook_set_mute_all(c, mixmonitor_spy_type, flag, clearmute);
|
||||
if (mutedcount < 0) {
|
||||
ast_channel_unref(c);
|
||||
astman_send_error(s, m, "Cannot set mute flag");
|
||||
return AMI_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
if (mute_mixmonitor_instance(c, mixmonitor_id, flag, clearmute)) {
|
||||
ast_channel_unref(c);
|
||||
astman_send_error(s, m, "Cannot set mute flag");
|
||||
return AMI_SUCCESS;
|
||||
}
|
||||
mutedcount = 1;
|
||||
}
|
||||
|
||||
stasis_message_blob = ast_json_pack("{s: s, s: b}",
|
||||
|
||||
stasis_message_blob = ast_json_pack("{s: s, s: b, s: s, s: i}",
|
||||
"direction", direction,
|
||||
"state", ast_true(state));
|
||||
"state", ast_true(state),
|
||||
"mixmonitorid", mixmonitor_id,
|
||||
"count", mutedcount);
|
||||
|
||||
stasis_message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(c),
|
||||
ast_channel_mixmonitor_mute_type(), stasis_message_blob);
|
||||
|
|
|
@ -101,7 +101,7 @@ static int mp3play(const char *filename, unsigned int sampling_rate, int fd)
|
|||
/* Execute mpg123, but buffer if it's a net connection */
|
||||
if (!strncasecmp(filename, "http://", 7) && strstr(filename, ".m3u")) {
|
||||
char buffer_size_str[8];
|
||||
snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); // 0.5 seconds for a live stream
|
||||
snprintf(buffer_size_str, 8, "%u", (int) 0.5*2*sampling_rate/1000); /* 0.5 seconds for a live stream */
|
||||
/* Most commonly installed in /usr/local/bin */
|
||||
execl(LOCAL_MPG_123, "mpg123", "-e", "s16", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, "-@", filename, (char *)NULL);
|
||||
/* But many places has it in /usr/bin */
|
||||
|
@ -111,7 +111,7 @@ static int mp3play(const char *filename, unsigned int sampling_rate, int fd)
|
|||
}
|
||||
else if (!strncasecmp(filename, "http://", 7)) {
|
||||
char buffer_size_str[8];
|
||||
snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); // 6 seconds for a remote MP3 file
|
||||
snprintf(buffer_size_str, 8, "%u", 6*2*sampling_rate/1000); /* 6 seconds for a remote MP3 file */
|
||||
/* Most commonly installed in /usr/local/bin */
|
||||
execl(LOCAL_MPG_123, "mpg123", "-e", "s16", "-q", "-s", "-b", buffer_size_str, "-f", "8192", "--mono", "-r", sampling_rate_str, filename, (char *)NULL);
|
||||
/* But many places has it in /usr/bin */
|
||||
|
|
|
@ -48,6 +48,13 @@
|
|||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="filenames" required="true" argsep="&">
|
||||
<para>Ampersand separated list of filenames. If the filename
|
||||
is a relative filename (it does not begin with a slash), it
|
||||
will be searched for in the Asterisk sounds directory. If the
|
||||
filename is able to be parsed as a URL, Asterisk will
|
||||
download the file and then begin playback on it. To include a
|
||||
literal <literal>&</literal> in the URL you can enclose
|
||||
the URL in single quotes.</para>
|
||||
<argument name="filename" required="true" />
|
||||
<argument name="filename2" multiple="true" />
|
||||
</parameter>
|
||||
|
@ -492,7 +499,7 @@ static int playback_exec(struct ast_channel *chan, const char *data)
|
|||
char *front;
|
||||
|
||||
ast_stopstream(chan);
|
||||
while (!res && (front = strsep(&back, "&"))) {
|
||||
while (!res && (front = ast_strsep(&back, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
|
||||
if (option_say)
|
||||
res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);
|
||||
else if (option_mix){
|
||||
|
@ -507,8 +514,7 @@ static int playback_exec(struct ast_channel *chan, const char *data)
|
|||
if (!res) {
|
||||
res = ast_waitstream(chan, "");
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
if (res) {
|
||||
} else {
|
||||
if (!ast_check_hangup(chan)) {
|
||||
ast_log(LOG_WARNING, "Playback failed on %s for %s\n", ast_channel_name(chan), (char *)data);
|
||||
}
|
||||
|
|
258
apps/app_queue.c
258
apps/app_queue.c
|
@ -161,7 +161,10 @@
|
|||
<para>Continue in the dialplan if the callee hangs up.</para>
|
||||
</option>
|
||||
<option name="d">
|
||||
<para>data-quality (modem) call (minimum delay).</para>
|
||||
<para>Data-quality (modem) call (minimum delay).</para>
|
||||
<para>This option only applies to DAHDI channels. By default,
|
||||
DTMF is verified by muting audio TX/RX to verify the tone
|
||||
is still present. This option disables that behavior.</para>
|
||||
</option>
|
||||
<option name="F" argsep="^">
|
||||
<argument name="context" required="false" />
|
||||
|
@ -171,12 +174,6 @@
|
|||
to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
</option>
|
||||
<option name="F">
|
||||
<para>When the caller hangs up, transfer the <emphasis>called member</emphasis> to the next priority of
|
||||
the current extension and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
<para>NOTE: Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
|
||||
</option>
|
||||
<option name="h">
|
||||
|
@ -244,11 +241,18 @@
|
|||
<para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
|
||||
</parameter>
|
||||
<parameter name="announceoverride" argsep="&">
|
||||
<argument name="filename" required="true">
|
||||
<para>Announcement file(s) to play to agent before bridging call, overriding the announcement(s)
|
||||
configured in <filename>queues.conf</filename>, if any.</para>
|
||||
</argument>
|
||||
<argument name="filename2" multiple="true" />
|
||||
<para>Announcement file(s) to play to agent before bridging
|
||||
call, overriding the announcement(s) configured in
|
||||
<filename>queues.conf</filename>, if any.</para>
|
||||
<para>Ampersand separated list of filenames. If the filename
|
||||
is a relative filename (it does not begin with a slash), it
|
||||
will be searched for in the Asterisk sounds directory. If the
|
||||
filename is able to be parsed as a URL, Asterisk will
|
||||
download the file and then begin playback on it. To include a
|
||||
literal <literal>&</literal> in the URL you can enclose
|
||||
the URL in single quotes.</para>
|
||||
<argument name="announceoverride" required="true" />
|
||||
<argument name="announceoverride2" multiple="true" />
|
||||
</parameter>
|
||||
<parameter name="timeout">
|
||||
<para>Will cause the queue to fail out after a specified number of
|
||||
|
@ -1062,6 +1066,9 @@
|
|||
<parameter name="Priority" required="true">
|
||||
<para>Priority value for change for caller on queue.</para>
|
||||
</parameter>
|
||||
<parameter name="Immediate">
|
||||
<para>When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
</description>
|
||||
|
@ -1277,7 +1284,7 @@
|
|||
</syntax>
|
||||
<see-also>
|
||||
<ref type="application">PauseQueueMember</ref>
|
||||
<ref type="application">UnPauseQueueMember</ref>
|
||||
<ref type="application">UnpauseQueueMember</ref>
|
||||
</see-also>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
|
@ -1621,9 +1628,15 @@ static int negative_penalty_invalid;
|
|||
/*! \brief queues.conf [general] option */
|
||||
static int log_membername_as_agent;
|
||||
|
||||
/*! \brief queues.conf [general] option */
|
||||
static int force_longest_waiting_caller;
|
||||
|
||||
/*! \brief name of the ringinuse field in the realtime database */
|
||||
static char *realtime_ringinuse_field;
|
||||
|
||||
/*! \brief does realtime backend support reason_paused */
|
||||
static int realtime_reason_paused;
|
||||
|
||||
enum queue_result {
|
||||
QUEUE_UNKNOWN = 0,
|
||||
QUEUE_TIMEOUT = 1,
|
||||
|
@ -1856,6 +1869,7 @@ struct call_queue {
|
|||
int announcepositionlimit; /*!< How many positions we announce? */
|
||||
int announcefrequency; /*!< How often to announce their position */
|
||||
int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
|
||||
int periodicannouncestartdelay; /*!< How long into the queue should the periodic accouncement start */
|
||||
int periodicannouncefrequency; /*!< How often to play periodic announcement */
|
||||
int numperiodicannounce; /*!< The number of periodic announcements configured */
|
||||
int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
|
||||
|
@ -2106,8 +2120,10 @@ static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, st
|
|||
/* every queue_ent must have a reference to it's parent call_queue, this
|
||||
* reference does not go away until the end of the queue_ent's life, meaning
|
||||
* that even when the queue_ent leaves the call_queue this ref must remain. */
|
||||
queue_ref(q);
|
||||
new->parent = q;
|
||||
if (!new->parent) {
|
||||
queue_ref(q);
|
||||
new->parent = q;
|
||||
}
|
||||
new->pos = ++(*pos);
|
||||
new->opos = *pos;
|
||||
}
|
||||
|
@ -2956,7 +2972,11 @@ static void init_queue(struct call_queue *q)
|
|||
q->timeout = DEFAULT_TIMEOUT;
|
||||
q->maxlen = 0;
|
||||
|
||||
ast_string_field_set(q, announce, "");
|
||||
ast_string_field_set(q, context, "");
|
||||
ast_string_field_set(q, membermacro, "");
|
||||
ast_string_field_set(q, membergosub, "");
|
||||
ast_string_field_set(q, defaultrule, "");
|
||||
|
||||
q->announcefrequency = 0;
|
||||
q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
|
||||
|
@ -2983,9 +3003,13 @@ static void init_queue(struct call_queue *q)
|
|||
q->weight = 0;
|
||||
q->timeoutrestart = 0;
|
||||
q->periodicannouncefrequency = 0;
|
||||
q->periodicannouncestartdelay = -1;
|
||||
q->randomperiodicannounce = 0;
|
||||
q->numperiodicannounce = 0;
|
||||
q->relativeperiodicannounce = 0;
|
||||
q->autopause = QUEUE_AUTOPAUSE_OFF;
|
||||
q->autopausebusy = 0;
|
||||
q->autopauseunavail = 0;
|
||||
q->timeoutpriority = TIMEOUT_PRIORITY_APP;
|
||||
q->autopausedelay = 0;
|
||||
if (!q->members) {
|
||||
|
@ -3010,6 +3034,7 @@ static void init_queue(struct call_queue *q)
|
|||
ast_string_field_set(q, sound_minute, "queue-minute");
|
||||
ast_string_field_set(q, sound_seconds, "queue-seconds");
|
||||
ast_string_field_set(q, sound_thanks, "queue-thankyou");
|
||||
ast_string_field_set(q, sound_callerannounce, "");
|
||||
ast_string_field_set(q, sound_reporthold, "queue-reporthold");
|
||||
|
||||
if (!q->sound_periodicannounce[0]) {
|
||||
|
@ -3437,6 +3462,8 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
|||
ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
|
||||
q->numperiodicannounce = 1;
|
||||
}
|
||||
} else if (!strcasecmp(param, "periodic-announce-startdelay")) {
|
||||
q->periodicannouncestartdelay = atoi(val);
|
||||
} else if (!strcasecmp(param, "periodic-announce-frequency")) {
|
||||
q->periodicannouncefrequency = atoi(val);
|
||||
} else if (!strcasecmp(param, "relative-periodic-announce")) {
|
||||
|
@ -3587,6 +3614,7 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
|
||||
const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
|
||||
const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
|
||||
const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
|
||||
|
||||
if (ast_strlen_zero(rt_uniqueid)) {
|
||||
ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
|
||||
|
@ -3653,6 +3681,9 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
m->penalty = penalty;
|
||||
m->ringinuse = ringinuse;
|
||||
m->wrapuptime = wrapuptime;
|
||||
if (realtime_reason_paused) {
|
||||
ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
|
||||
}
|
||||
found = 1;
|
||||
ao2_ref(m, -1);
|
||||
break;
|
||||
|
@ -3667,6 +3698,9 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
m->dead = 0;
|
||||
m->realtime = 1;
|
||||
ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
|
||||
if (!ast_strlen_zero(reason_paused)) {
|
||||
ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
|
||||
}
|
||||
if (!log_membername_as_agent) {
|
||||
ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
|
||||
} else {
|
||||
|
@ -4560,6 +4594,56 @@ static int compare_weight(struct call_queue *rq, struct member *member)
|
|||
return found;
|
||||
}
|
||||
|
||||
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
|
||||
{
|
||||
struct call_queue *q;
|
||||
struct member *mem;
|
||||
int is_longest_waiting = 1;
|
||||
struct ao2_iterator queue_iter;
|
||||
struct queue_ent *ch;
|
||||
|
||||
queue_iter = ao2_iterator_init(queues, 0);
|
||||
while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
|
||||
if (q == caller->parent) { /* don't check myself, could deadlock */
|
||||
queue_t_unref(q, "Done with iterator");
|
||||
continue;
|
||||
}
|
||||
ao2_lock(q);
|
||||
/*
|
||||
* If the other queue has equal weight, see if we should let that handle
|
||||
* their call first. If weights are not equal, compare_weights will step in.
|
||||
*/
|
||||
if (q->weight == caller->parent->weight && q->count && q->members) {
|
||||
if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
|
||||
ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
|
||||
|
||||
/* Does this queue have a caller that's been waiting longer? */
|
||||
ch = q->head;
|
||||
while (ch) {
|
||||
/* If ch->pending, the other call (which may be waiting for a longer period of time),
|
||||
* is already ringing at another agent. Ignore such callers; otherwise, all agents
|
||||
* will be unused until the first caller is picked up.
|
||||
*/
|
||||
if (ch->start < caller->start && !ch->pending) {
|
||||
ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
|
||||
q->name, ch->pos, ch->start, caller->start);
|
||||
is_longest_waiting = 0;
|
||||
break;
|
||||
}
|
||||
ch = ch->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
ao2_unlock(q);
|
||||
queue_t_unref(q, "Done with iterator");
|
||||
if (!is_longest_waiting) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&queue_iter);
|
||||
return is_longest_waiting;
|
||||
}
|
||||
|
||||
/*! \brief common hangup actions */
|
||||
static void do_hang(struct callattempt *o)
|
||||
{
|
||||
|
@ -4624,6 +4708,12 @@ static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (force_longest_waiting_caller && !is_longest_waiting_caller(qe, memberp)) {
|
||||
ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
|
||||
qe->parent->name, call->interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!memberp->ringinuse) {
|
||||
struct member *mem;
|
||||
|
||||
|
@ -7161,7 +7251,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
if (!res2 && announce) {
|
||||
char *front;
|
||||
char *announcefiles = ast_strdupa(announce);
|
||||
while ((front = strsep(&announcefiles, "&"))) {
|
||||
while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
|
||||
if (play_file(peer, front) < 0) {
|
||||
ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
|
||||
}
|
||||
|
@ -7637,10 +7727,10 @@ static int add_to_queue(const char *queuename, const char *interface, const char
|
|||
* \retval RES_OKAY change priority
|
||||
* \retval RES_NOT_CALLER queue exists but no caller
|
||||
*/
|
||||
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority)
|
||||
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
|
||||
{
|
||||
struct call_queue *q;
|
||||
struct queue_ent *qe;
|
||||
struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
|
||||
int res = RES_NOSUCHQUEUE;
|
||||
|
||||
/*! \note Ensure the appropriate realtime queue is loaded. Note that this
|
||||
|
@ -7651,14 +7741,57 @@ static int change_priority_caller_on_queue(const char *queuename, const char *ca
|
|||
|
||||
ao2_lock(q);
|
||||
res = RES_NOT_CALLER;
|
||||
for (qe = q->head; qe; qe = qe->next) {
|
||||
if (strcmp(ast_channel_name(qe->chan), caller) == 0) {
|
||||
for (current = q->head; current; current = current->next) {
|
||||
if (strcmp(ast_channel_name(current->chan), caller) == 0) {
|
||||
ast_debug(1, "%s Caller new priority %d in queue %s\n",
|
||||
caller, priority, queuename);
|
||||
qe->prio = priority;
|
||||
current->prio = priority;
|
||||
if (immediate) {
|
||||
/* This caller is being immediately moved in the queue so remove them */
|
||||
if (prev) {
|
||||
prev->next = current->next;
|
||||
} else {
|
||||
q->head = current->next;
|
||||
}
|
||||
caller_qe = current;
|
||||
/* The position for all callers is not recalculated in here as it will
|
||||
* be updated when the moved caller is inserted back into the queue
|
||||
*/
|
||||
}
|
||||
res = RES_OKAY;
|
||||
break;
|
||||
} else if (immediate) {
|
||||
prev = current;
|
||||
}
|
||||
}
|
||||
|
||||
if (caller_qe) {
|
||||
int inserted = 0, pos = 0;
|
||||
|
||||
/* If a caller queue entry exists, we are applying their priority immediately
|
||||
* and have to reinsert them at the correct position.
|
||||
*/
|
||||
prev = NULL;
|
||||
current = q->head;
|
||||
while (current) {
|
||||
if (!inserted && (caller_qe->prio > current->prio)) {
|
||||
insert_entry(q, prev, caller_qe, &pos);
|
||||
inserted = 1;
|
||||
}
|
||||
|
||||
/* We always update the position as it may have changed */
|
||||
current->pos = ++pos;
|
||||
|
||||
/* Move to the next caller in the queue */
|
||||
prev = current;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (!inserted) {
|
||||
insert_entry(q, prev, caller_qe, &pos);
|
||||
}
|
||||
}
|
||||
|
||||
ao2_unlock(q);
|
||||
return res;
|
||||
}
|
||||
|
@ -7740,10 +7873,17 @@ static void set_queue_member_pause(struct call_queue *q, struct member *mem, con
|
|||
(paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
|
||||
}
|
||||
|
||||
if (mem->realtime) {
|
||||
if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
|
||||
ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
|
||||
(paused ? "" : "un"), q->name, mem->interface);
|
||||
if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
|
||||
if (realtime_reason_paused) {
|
||||
if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
|
||||
ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
|
||||
q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
|
||||
}
|
||||
} else {
|
||||
if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
|
||||
ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
|
||||
(paused ? "" : "un"), q->name, mem->interface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7754,6 +7894,9 @@ static void set_queue_member_pause(struct call_queue *q, struct member *mem, con
|
|||
if (paused && !ast_strlen_zero(reason)) {
|
||||
ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
|
||||
} else {
|
||||
/* We end up filling this in again later (temporarily) but we need it
|
||||
* empty for now so that the intervening code - specifically
|
||||
* dump_queue_members() - has the correct view of things. */
|
||||
mem->reason_paused[0] = '\0';
|
||||
}
|
||||
|
||||
|
@ -7772,10 +7915,22 @@ static void set_queue_member_pause(struct call_queue *q, struct member *mem, con
|
|||
"Queue:%s_avail", q->name);
|
||||
}
|
||||
|
||||
ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"),
|
||||
"%s", S_OR(reason, ""));
|
||||
if (!paused && !ast_strlen_zero(reason)) {
|
||||
/* Because we've been unpaused with a 'reason' we need to ensure that
|
||||
* that reason is emitted when the subsequent PauseQueueMember event
|
||||
* is raised. So temporarily set it on the member and clear it out
|
||||
* again right after. */
|
||||
ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
|
||||
}
|
||||
|
||||
ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
|
||||
"%s", mem->reason_paused);
|
||||
|
||||
publish_queue_member_pause(q, mem);
|
||||
|
||||
if (!paused) {
|
||||
mem->reason_paused[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
|
||||
|
@ -8172,7 +8327,7 @@ static int pqm_exec(struct ast_channel *chan, const char *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief UnPauseQueueMember application */
|
||||
/*! \brief UnpauseQueueMember application */
|
||||
static int upqm_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *parse;
|
||||
|
@ -8193,7 +8348,7 @@ static int upqm_exec(struct ast_channel *chan, const char *data)
|
|||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.interface)) {
|
||||
ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
|
||||
ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -8614,6 +8769,11 @@ static int queue_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
ast_assert(qe.parent != NULL);
|
||||
|
||||
if (qe.parent->periodicannouncestartdelay >= 0) {
|
||||
qe.last_periodic_announce_time += qe.parent->periodicannouncestartdelay;
|
||||
qe.last_periodic_announce_time -= qe.parent->periodicannouncefrequency;
|
||||
}
|
||||
|
||||
ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
|
||||
S_OR(args.url, ""),
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
|
||||
|
@ -9498,6 +9658,7 @@ static void queue_reset_global_params(void)
|
|||
shared_lastcall = 0;
|
||||
negative_penalty_invalid = 0;
|
||||
log_membername_as_agent = 0;
|
||||
force_longest_waiting_caller = 0;
|
||||
}
|
||||
|
||||
/*! Set the global queue parameters as defined in the "general" section of queues.conf */
|
||||
|
@ -9523,6 +9684,9 @@ static void queue_set_global_params(struct ast_config *cfg)
|
|||
if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
|
||||
log_membername_as_agent = ast_true(general_val);
|
||||
}
|
||||
if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
|
||||
force_longest_waiting_caller = ast_true(general_val);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief reload information pertaining to a single member
|
||||
|
@ -10824,12 +10988,13 @@ static int manager_queue_member_penalty(struct mansession *s, const struct messa
|
|||
|
||||
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
|
||||
{
|
||||
const char *queuename, *caller, *priority_s;
|
||||
int priority = 0;
|
||||
const char *queuename, *caller, *priority_s, *immediate_s;
|
||||
int priority = 0, immediate = 0;
|
||||
|
||||
queuename = astman_get_header(m, "Queue");
|
||||
caller = astman_get_header(m, "Caller");
|
||||
priority_s = astman_get_header(m, "Priority");
|
||||
immediate_s = astman_get_header(m, "Immediate");
|
||||
|
||||
if (ast_strlen_zero(queuename)) {
|
||||
astman_send_error(s, m, "'Queue' not specified.");
|
||||
|
@ -10849,7 +11014,11 @@ static int manager_change_priority_caller_on_queue(struct mansession *s, const s
|
|||
return 0;
|
||||
}
|
||||
|
||||
switch (change_priority_caller_on_queue(queuename, caller, priority)) {
|
||||
if (!ast_strlen_zero(immediate_s)) {
|
||||
immediate = ast_true(immediate_s);
|
||||
}
|
||||
|
||||
switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
|
||||
case RES_OKAY:
|
||||
astman_send_ack(s, m, "Priority change for caller on queue");
|
||||
break;
|
||||
|
@ -10910,7 +11079,7 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as
|
|||
case CLI_INIT:
|
||||
e->command = "queue add member";
|
||||
e->usage =
|
||||
"Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
|
||||
"Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface>]]]\n"
|
||||
" Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
|
@ -11093,21 +11262,21 @@ static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct
|
|||
static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
const char *queuename, *caller;
|
||||
int priority;
|
||||
int priority, immediate = 0;
|
||||
char *res = CLI_FAILURE;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "queue priority caller";
|
||||
e->usage =
|
||||
"Usage: queue priority caller <channel> on <queue> to <priority>\n"
|
||||
" Change the priority of a channel on a queue.\n";
|
||||
"Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
|
||||
" Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != 8) {
|
||||
if (a->argc < 8) {
|
||||
return CLI_SHOWUSAGE;
|
||||
} else if (strcmp(a->argv[4], "on")) {
|
||||
return CLI_SHOWUSAGE;
|
||||
|
@ -11116,12 +11285,17 @@ static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cm
|
|||
} else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
|
||||
ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
|
||||
return CLI_SHOWUSAGE;
|
||||
} else if (a->argc == 9) {
|
||||
if (strcmp(a->argv[8], "immediate")) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
immediate = 1;
|
||||
}
|
||||
|
||||
caller = a->argv[3];
|
||||
queuename = a->argv[5];
|
||||
|
||||
switch (change_priority_caller_on_queue(queuename, caller, priority)) {
|
||||
switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
|
||||
case RES_OKAY:
|
||||
res = CLI_SUCCESS;
|
||||
break;
|
||||
|
@ -11693,11 +11867,13 @@ static int load_module(void)
|
|||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
|
||||
ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
|
||||
|
||||
/*
|
||||
* This section is used to determine which name for 'ringinuse' to use in realtime members
|
||||
* Necessary for supporting older setups.
|
||||
*
|
||||
* It also checks if 'reason_paused' exists in the realtime backend
|
||||
*/
|
||||
member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
|
||||
if (!member_config) {
|
||||
|
@ -11715,6 +11891,10 @@ static int load_module(void)
|
|||
ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
|
||||
realtime_ringinuse_field = "ringinuse";
|
||||
}
|
||||
|
||||
if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
|
||||
realtime_reason_paused = 1;
|
||||
}
|
||||
}
|
||||
ast_config_destroy(member_config);
|
||||
|
||||
|
|
|
@ -49,9 +49,15 @@
|
|||
name.</para>
|
||||
</parameter>
|
||||
<parameter name="filenames" argsep="&">
|
||||
<argument name="filename" required="true">
|
||||
<para>file(s) to play before reading digits or tone with option i</para>
|
||||
</argument>
|
||||
<para>Ampersand separated list of filenames to play before
|
||||
reading digits or tone with option <literal>i</literal>. If
|
||||
the filename is a relative filename (it does not begin with a
|
||||
slash), it will be searched for in the Asterisk sounds
|
||||
directory. If the filename is able to be parsed as a URL,
|
||||
Asterisk will download the file and then begin playback on
|
||||
it. To include a literal <literal>&</literal> in the URL
|
||||
you can enclose the URL in single quotes.</para>
|
||||
<argument name="filename" required="true" />
|
||||
<argument name="filename2" multiple="true" />
|
||||
</parameter>
|
||||
<parameter name="maxdigits">
|
||||
|
@ -85,6 +91,13 @@
|
|||
and you will need to rely on duration and max digits
|
||||
for ending input.</para>
|
||||
</option>
|
||||
<option name="e">
|
||||
<para>to read the terminator as the digit string if the
|
||||
only digit read is the terminator. This is for cases
|
||||
where the terminator is a valid digit, but only by itself.
|
||||
ie; <literal>1234</literal> and <literal>#</literal> are
|
||||
valid, but <literal>1234#</literal> is not.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
<parameter name="attempts">
|
||||
|
@ -125,6 +138,7 @@ enum read_option_flags {
|
|||
OPT_INDICATION = (1 << 1),
|
||||
OPT_NOANSWER = (1 << 2),
|
||||
OPT_TERMINATOR = (1 << 3),
|
||||
OPT_KEEP_TERMINATOR = (1 << 4),
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -138,6 +152,7 @@ AST_APP_OPTIONS(read_app_options, {
|
|||
AST_APP_OPTION('i', OPT_INDICATION),
|
||||
AST_APP_OPTION('n', OPT_NOANSWER),
|
||||
AST_APP_OPTION_ARG('t', OPT_TERMINATOR, OPT_ARG_TERMINATOR),
|
||||
AST_APP_OPTION('e', OPT_KEEP_TERMINATOR),
|
||||
});
|
||||
|
||||
static char *app = "Read";
|
||||
|
@ -261,12 +276,20 @@ static int read_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
} else {
|
||||
res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);
|
||||
if (res == AST_GETDATA_COMPLETE || res == AST_GETDATA_EMPTY_END_TERMINATED)
|
||||
if (res == AST_GETDATA_COMPLETE) {
|
||||
status = "OK";
|
||||
else if (res == AST_GETDATA_TIMEOUT)
|
||||
} else if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
|
||||
if (ast_test_flag(&flags, OPT_KEEP_TERMINATOR)) {
|
||||
/* if the option is set to do so, read the
|
||||
returned string as the terminator string */
|
||||
ast_copy_string(tmp, terminator, sizeof(tmp));
|
||||
}
|
||||
status = "OK";
|
||||
} else if (res == AST_GETDATA_TIMEOUT) {
|
||||
status = "TIMEOUT";
|
||||
else if (res == AST_GETDATA_INTERRUPTED)
|
||||
} else if (res == AST_GETDATA_INTERRUPTED) {
|
||||
status = "INTERRUPTED";
|
||||
}
|
||||
}
|
||||
if (res > -1) {
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
|
||||
|
|
|
@ -57,6 +57,15 @@
|
|||
<parameter name="channel" required="false">
|
||||
<para>Channel where digits will be played</para>
|
||||
</parameter>
|
||||
<parameter name="options">
|
||||
<optionlist>
|
||||
<option name="a">
|
||||
<para>Answer the channel specified by the <literal>channel</literal>
|
||||
parameter if it is not already up. If no <literal>channel</literal>
|
||||
parameter is provided, the current channel will be answered.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>It will send all digits or terminate if it encounters an error.</para>
|
||||
|
@ -88,8 +97,38 @@
|
|||
<para>Plays a dtmf digit on the specified channel.</para>
|
||||
</description>
|
||||
</manager>
|
||||
<manager name="SendFlash" language="en_US">
|
||||
<synopsis>
|
||||
Send a hook flash on a specific channel.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
||||
<parameter name="Channel" required="true">
|
||||
<para>Channel name to send hook flash to.</para>
|
||||
</parameter>
|
||||
<parameter name="Receive" required="false">
|
||||
<para>Emulate receiving a hook flash on this channel instead of sending it out.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Sends a hook flash on the specified channel.</para>
|
||||
</description>
|
||||
</manager>
|
||||
***/
|
||||
|
||||
enum read_option_flags {
|
||||
OPT_ANSWER = (1 << 0),
|
||||
};
|
||||
|
||||
AST_APP_OPTIONS(senddtmf_app_options, {
|
||||
AST_APP_OPTION('a', OPT_ANSWER),
|
||||
});
|
||||
|
||||
enum {
|
||||
/* note: this entry _MUST_ be the last one in the enum */
|
||||
OPT_ARG_ARRAY_SIZE,
|
||||
};
|
||||
|
||||
static const char senddtmf_name[] = "SendDTMF";
|
||||
|
||||
static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
|
||||
|
@ -100,11 +139,14 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
|
|||
struct ast_channel *chan_found = NULL;
|
||||
struct ast_channel *chan_dest = chan;
|
||||
struct ast_channel *chan_autoservice = NULL;
|
||||
char *opt_args[OPT_ARG_ARRAY_SIZE];
|
||||
struct ast_flags flags = {0};
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(digits);
|
||||
AST_APP_ARG(dinterval);
|
||||
AST_APP_ARG(duration);
|
||||
AST_APP_ARG(channel);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(vdata)) {
|
||||
|
@ -136,6 +178,12 @@ static int senddtmf_exec(struct ast_channel *chan, const char *vdata)
|
|||
chan_autoservice = chan;
|
||||
}
|
||||
}
|
||||
if (!ast_strlen_zero(args.options)) {
|
||||
ast_app_parse_options(senddtmf_app_options, &flags, opt_args, args.options);
|
||||
}
|
||||
if (ast_test_flag(&flags, OPT_ANSWER)) {
|
||||
ast_auto_answer(chan_dest);
|
||||
}
|
||||
res = ast_dtmf_stream(chan_dest, chan_autoservice, args.digits,
|
||||
dinterval <= 0 ? 250 : dinterval, duration);
|
||||
if (chan_found) {
|
||||
|
@ -187,12 +235,41 @@ static int manager_play_dtmf(struct mansession *s, const struct message *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int manager_send_flash(struct mansession *s, const struct message *m)
|
||||
{
|
||||
const char *channel = astman_get_header(m, "Channel");
|
||||
const char *receive_s = astman_get_header(m, "Receive");
|
||||
struct ast_channel *chan;
|
||||
|
||||
if (!(chan = ast_channel_get_by_name(channel))) {
|
||||
astman_send_error(s, m, "Channel not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_true(receive_s)) {
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, };
|
||||
f.subclass.integer = AST_CONTROL_FLASH;
|
||||
ast_queue_frame(chan, &f);
|
||||
} else {
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, };
|
||||
f.subclass.integer = AST_CONTROL_FLASH;
|
||||
ast_channel_lock(chan);
|
||||
ast_write(chan, &f);
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
||||
chan = ast_channel_unref(chan);
|
||||
astman_send_ack(s, m, "Flash successfully queued");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(senddtmf_name);
|
||||
res |= ast_manager_unregister("PlayDTMF");
|
||||
res |= ast_manager_unregister("SendFlash");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -202,6 +279,7 @@ static int load_module(void)
|
|||
int res;
|
||||
|
||||
res = ast_manager_register_xml("PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf);
|
||||
res |= ast_manager_register_xml("SendFlash", EVENT_FLAG_CALL, manager_send_flash);
|
||||
res |= ast_register_application_xml(senddtmf_name, senddtmf_exec);
|
||||
|
||||
return res;
|
||||
|
|
|
@ -139,8 +139,6 @@
|
|||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">SendImage</ref>
|
||||
<ref type="application">SendURL</ref>
|
||||
<ref type="application">ReceiveText</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
|
@ -182,8 +180,6 @@
|
|||
</description>
|
||||
<see-also>
|
||||
<ref type="application">SendText</ref>
|
||||
<ref type="application">SendImage</ref>
|
||||
<ref type="application">SendURL</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2022, Naveen Albert
|
||||
*
|
||||
* Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Channel signaling applications
|
||||
*
|
||||
* \author Naveen Albert <asterisk@phreaknet.org>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>extended</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="Signal" language="en_US">
|
||||
<synopsis>
|
||||
Sends a signal to any waiting channels.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="signalname" required="true">
|
||||
<para>Name of signal to send.</para>
|
||||
</parameter>
|
||||
<parameter name="payload" required="false">
|
||||
<para>Payload data to deliver.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Sends a named signal to any channels that may be
|
||||
waiting for one. Acts as a producer in a simple
|
||||
message queue.</para>
|
||||
<variablelist>
|
||||
<variable name="SIGNALSTATUS">
|
||||
<value name="SUCCESS">
|
||||
Signal was successfully sent to at least
|
||||
one listener for processing.
|
||||
</value>
|
||||
<value name="FAILURE">
|
||||
Signal could not be sent or nobody
|
||||
was listening for this signal.
|
||||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
<example title="Send a signal named workdone">
|
||||
same => n,Signal(workdone,Work has completed)
|
||||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">WaitForSignal</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
<application name="WaitForSignal" language="en_US">
|
||||
<synopsis>
|
||||
Waits for a named signal on a channel.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="signalname" required="true">
|
||||
<para>Name of signal to send.</para>
|
||||
</parameter>
|
||||
<parameter name="signaltimeout" required="false">
|
||||
<para>Maximum time, in seconds, to wait for signal.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Waits for <replaceable>signaltimeout</replaceable> seconds on the current
|
||||
channel to receive a signal with name <replaceable>signalname</replaceable>.
|
||||
Acts as a consumer in a simple message queue.</para>
|
||||
<para>Result of signal wait will be stored in the following variables:</para>
|
||||
<variablelist>
|
||||
<variable name="WAITFORSIGNALSTATUS">
|
||||
<value name="SIGNALED">
|
||||
Signal was received.
|
||||
</value>
|
||||
<value name="TIMEOUT">
|
||||
Timed out waiting for signal.
|
||||
</value>
|
||||
<value name="HANGUP">
|
||||
Channel hung up before signal was received.
|
||||
</value>
|
||||
</variable>
|
||||
<variable name="WAITFORSIGNALPAYLOAD">
|
||||
<para>Data payload attached to signal, if it exists</para>
|
||||
</variable>
|
||||
</variablelist>
|
||||
<example title="Wait for the workdone signal, indefinitely, and print out payload">
|
||||
same => n,WaitForSignal(workdone)
|
||||
same => n,NoOp(Received: ${WAITFORSIGNALPAYLOAD})
|
||||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="application">Signal</ref>
|
||||
</see-also>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static const char * const app = "Signal";
|
||||
static const char * const app2 = "WaitForSignal";
|
||||
|
||||
struct signalitem {
|
||||
ast_mutex_t lock;
|
||||
char name[AST_MAX_CONTEXT];
|
||||
int sig_alert_pipe[2];
|
||||
int watchers;
|
||||
unsigned int signaled:1;
|
||||
char *payload;
|
||||
AST_LIST_ENTRY(signalitem) entry; /*!< Next Signal item */
|
||||
};
|
||||
|
||||
static AST_RWLIST_HEAD_STATIC(signals, signalitem);
|
||||
|
||||
static struct signalitem *alloc_signal(const char *sname)
|
||||
{
|
||||
struct signalitem *s;
|
||||
|
||||
if (!(s = ast_calloc(1, sizeof(*s)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_mutex_init(&s->lock);
|
||||
ast_copy_string(s->name, sname, sizeof(s->name));
|
||||
|
||||
s->sig_alert_pipe[0] = -1;
|
||||
s->sig_alert_pipe[1] = -1;
|
||||
s->watchers = 0;
|
||||
s->payload = NULL;
|
||||
ast_alertpipe_init(s->sig_alert_pipe);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int dealloc_signal(struct signalitem *s)
|
||||
{
|
||||
if (s->watchers) { /* somebody is still using us... refuse to go away */
|
||||
ast_debug(1, "Signal '%s' is still being used by %d listener(s)\n", s->name, s->watchers);
|
||||
return -1;
|
||||
}
|
||||
ast_alertpipe_close(s->sig_alert_pipe);
|
||||
ast_mutex_destroy(&s->lock);
|
||||
if (s->payload) {
|
||||
ast_free(s->payload);
|
||||
s->payload = NULL;
|
||||
}
|
||||
ast_free(s);
|
||||
s = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remove_signal(char *sname)
|
||||
{
|
||||
int res = -1;
|
||||
struct signalitem *s;
|
||||
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&signals, s, entry) {
|
||||
if (!strcmp(s->name, sname)) {
|
||||
AST_LIST_REMOVE_CURRENT(entry);
|
||||
res = dealloc_signal(s);
|
||||
ast_debug(1, "Removed signal '%s'\n", sname);
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct signalitem *get_signal(char *sname, int addnew)
|
||||
{
|
||||
struct signalitem *s = NULL;
|
||||
AST_RWLIST_WRLOCK(&signals);
|
||||
AST_LIST_TRAVERSE(&signals, s, entry) {
|
||||
if (!strcasecmp(s->name, sname)) {
|
||||
ast_debug(1, "Using existing signal item '%s'\n", sname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!s) {
|
||||
if (addnew) { /* signal doesn't exist, so create it */
|
||||
s = alloc_signal(sname);
|
||||
/* Totally fail if we fail to find/create an entry */
|
||||
if (s) {
|
||||
ast_debug(1, "Created new signal item '%s'\n", sname);
|
||||
AST_RWLIST_INSERT_HEAD(&signals, s, entry);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Failed to create signal item for '%s'\n", sname);
|
||||
}
|
||||
} else {
|
||||
ast_debug(1, "Signal '%s' doesn't exist, and not creating it\n", sname);
|
||||
}
|
||||
}
|
||||
AST_RWLIST_UNLOCK(&signals);
|
||||
return s;
|
||||
}
|
||||
|
||||
static int wait_for_signal_or_hangup(struct ast_channel *chan, char *signame, int timeout)
|
||||
{
|
||||
struct signalitem *s = NULL;
|
||||
int ms, remaining_time, res = 1, goaway = 0;
|
||||
struct timeval start;
|
||||
struct ast_frame *frame = NULL;
|
||||
|
||||
remaining_time = timeout;
|
||||
start = ast_tvnow();
|
||||
|
||||
s = get_signal(signame, 1);
|
||||
|
||||
ast_mutex_lock(&s->lock);
|
||||
s->watchers = s->watchers + 1; /* we unlock, because a) other people need to use this and */
|
||||
ast_mutex_unlock(&s->lock); /* b) the signal will be available to us as long as watchers > 0 */
|
||||
|
||||
while (timeout == 0 || remaining_time > 0) {
|
||||
int ofd, exception;
|
||||
|
||||
ms = 1000;
|
||||
errno = 0;
|
||||
if (ast_waitfor_nandfds(&chan, 1, &s->sig_alert_pipe[0], 1, &exception, &ofd, &ms)) { /* channel won */
|
||||
if (!(frame = ast_read(chan))) { /* channel hung up */
|
||||
ast_debug(1, "Channel '%s' did not return a frame; probably hung up.\n", ast_channel_name(chan));
|
||||
res = -1;
|
||||
break;
|
||||
} else {
|
||||
ast_frfree(frame); /* handle frames */
|
||||
}
|
||||
} else if (ofd == s->sig_alert_pipe[0]) { /* fd won */
|
||||
if (ast_alertpipe_read(s->sig_alert_pipe) == AST_ALERT_READ_SUCCESS) {
|
||||
ast_debug(1, "Alert pipe has data for us\n");
|
||||
res = 0;
|
||||
break;
|
||||
} else {
|
||||
ast_debug(1, "Alert pipe does not have data for us\n");
|
||||
}
|
||||
} else { /* nobody won */
|
||||
if (ms && (ofd < 0)) {
|
||||
if (!((errno == 0) || (errno == EINTR))) {
|
||||
ast_log(LOG_WARNING, "Something bad happened while channel '%s' was polling.\n", ast_channel_name(chan));
|
||||
break;
|
||||
}
|
||||
} /* else, nothing happened */
|
||||
}
|
||||
if (timeout) {
|
||||
remaining_time = ast_remaining_ms(start, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* WRLOCK the list so that if we're going to destroy the signal now, nobody else can grab it before that happens. */
|
||||
AST_RWLIST_WRLOCK(&signals);
|
||||
ast_mutex_lock(&s->lock);
|
||||
if (s->payload) {
|
||||
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALPAYLOAD", s->payload);
|
||||
}
|
||||
s->watchers = s->watchers - 1;
|
||||
if (s->watchers) { /* folks are still waiting for this, pass it on... */
|
||||
int save_errno = errno;
|
||||
if (ast_alertpipe_write(s->sig_alert_pipe)) {
|
||||
ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
|
||||
}
|
||||
errno = save_errno;
|
||||
} else { /* nobody else is waiting for this */
|
||||
goaway = 1; /* we were the last guy using this, so mark signal item for destruction */
|
||||
}
|
||||
ast_mutex_unlock(&s->lock);
|
||||
|
||||
if (goaway) {
|
||||
/* remove_signal calls ast_mutex_destroy, so don't call it with the mutex itself locked. */
|
||||
remove_signal(signame);
|
||||
}
|
||||
AST_RWLIST_UNLOCK(&signals);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int send_signal(char *signame, char *payload)
|
||||
{
|
||||
struct signalitem *s;
|
||||
int save_errno = errno;
|
||||
int res = 0;
|
||||
|
||||
s = get_signal(signame, 0); /* if signal doesn't exist already, no point in creating it, because nobody could be waiting for it! */
|
||||
|
||||
if (!s) {
|
||||
return -1; /* this signal didn't exist, so we can't send a signal for it */
|
||||
}
|
||||
|
||||
/* at this point, we know someone is listening, since signals are destroyed when watchers gets down to 0 */
|
||||
ast_mutex_lock(&s->lock);
|
||||
s->signaled = 1;
|
||||
if (payload && *payload) {
|
||||
int len = strlen(payload);
|
||||
if (s->payload) {
|
||||
ast_free(s->payload); /* if there was already a payload, replace it */
|
||||
s->payload = NULL;
|
||||
}
|
||||
s->payload = ast_malloc(len + 1);
|
||||
if (!s->payload) {
|
||||
ast_log(LOG_WARNING, "Failed to allocate signal payload '%s'\n", payload);
|
||||
} else {
|
||||
ast_copy_string(s->payload, payload, len + 1);
|
||||
}
|
||||
}
|
||||
if (ast_alertpipe_write(s->sig_alert_pipe)) {
|
||||
ast_log(LOG_WARNING, "%s: write() failed: %s\n", __FUNCTION__, strerror(errno));
|
||||
s->signaled = 0; /* okay, so we didn't send a signal after all... */
|
||||
res = -1;
|
||||
}
|
||||
errno = save_errno;
|
||||
ast_debug(1, "Sent '%s' signal to %d listeners\n", signame, s->watchers);
|
||||
ast_mutex_unlock(&s->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int waitsignal_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *argcopy;
|
||||
int r = 0, timeoutms = 0;
|
||||
double timeout = 0;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(signame);
|
||||
AST_APP_ARG(sigtimeout);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Signal() requires arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
argcopy = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, argcopy);
|
||||
|
||||
if (ast_strlen_zero(args.signame)) {
|
||||
ast_log(LOG_WARNING, "Missing signal name\n");
|
||||
return -1;
|
||||
}
|
||||
if (strlen(args.signame) >= AST_MAX_CONTEXT) {
|
||||
ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
|
||||
return -1;
|
||||
}
|
||||
if (!ast_strlen_zero(args.sigtimeout)) {
|
||||
if (sscanf(args.sigtimeout, "%30lg", &timeout) != 1 || timeout < 0) {
|
||||
ast_log(LOG_WARNING, "Invalid timeout provided: %s. Defaulting to no timeout.\n", args.sigtimeout);
|
||||
} else {
|
||||
timeoutms = timeout * 1000; /* sec to msec */
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
ast_debug(1, "Waiting for signal '%s' for %d ms\n", args.signame, timeoutms);
|
||||
} else {
|
||||
ast_debug(1, "Waiting for signal '%s', indefinitely\n", args.signame);
|
||||
}
|
||||
|
||||
r = wait_for_signal_or_hangup(chan, args.signame, timeoutms);
|
||||
|
||||
if (r == 1) {
|
||||
ast_verb(3, "Channel '%s' timed out, waiting for signal '%s'\n", ast_channel_name(chan), args.signame);
|
||||
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "TIMEOUT");
|
||||
} else if (!r) {
|
||||
ast_verb(3, "Received signal '%s' on channel '%s'\n", args.signame, ast_channel_name(chan));
|
||||
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "SIGNALED");
|
||||
} else {
|
||||
pbx_builtin_setvar_helper(chan, "WAITFORSIGNALSTATUS", "HANGUP");
|
||||
ast_verb(3, "Channel '%s' hung up\n", ast_channel_name(chan));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int signal_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *argcopy;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(signame);
|
||||
AST_APP_ARG(payload);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Signal() requires arguments\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
argcopy = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, argcopy);
|
||||
|
||||
if (ast_strlen_zero(args.signame)) {
|
||||
ast_log(LOG_WARNING, "Missing signal name\n");
|
||||
return -1;
|
||||
}
|
||||
if (strlen(args.signame) >= AST_MAX_CONTEXT) {
|
||||
ast_log(LOG_WARNING, "Signal name '%s' is too long\n", args.signame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send_signal(args.signame, args.payload)) {
|
||||
pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "FAILURE");
|
||||
} else {
|
||||
pbx_builtin_setvar_helper(chan, "SIGNALSTATUS", "SUCCESS");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
struct signalitem *s;
|
||||
int res = 0;
|
||||
|
||||
/* To avoid a locking nightmare, and for logistical reasons, this module
|
||||
* will refuse to unload if watchers > 0. That way we know a signal's
|
||||
* pipe won't disappear while it's being used. */
|
||||
|
||||
AST_RWLIST_WRLOCK(&signals);
|
||||
/* Don't just use AST_RWLIST_REMOVE_HEAD, because if dealloc_signal fails, it should stay in the list. */
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&signals, s, entry) {
|
||||
int mres = dealloc_signal(s);
|
||||
res |= mres;
|
||||
if (!mres) {
|
||||
AST_LIST_REMOVE_CURRENT(entry);
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_RWLIST_UNLOCK(&signals);
|
||||
|
||||
/* One or more signals still has watchers. */
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "One or more signals is currently in use. Unload failed.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
res |= ast_unregister_application(app);
|
||||
res |= ast_unregister_application(app2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application_xml(app, signal_exec);
|
||||
res |= ast_register_application_xml(app2, waitsignal_exec);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Channel Signaling Applications");
|
|
@ -16,7 +16,7 @@
|
|||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* https://wiki.asterisk.org/wiki/display/AST/Coding+Guidelines
|
||||
* https://docs.asterisk.org/Development/Policies-and-Procedures/Coding-Guidelines/
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
@ -371,7 +371,8 @@ static void play_files_helper(struct ast_channel *chan, const char *prompts)
|
|||
char *prompt, *rest = ast_strdupa(prompts);
|
||||
|
||||
ast_stopstream(chan);
|
||||
while ((prompt = strsep(&rest, "&")) && !ast_stream_and_wait(chan, prompt, "")) {
|
||||
while ((prompt = ast_strsep(&rest, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))
|
||||
&& !ast_stream_and_wait(chan, prompt, "")) {
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,17 @@
|
|||
Play a sound file and wait for speech to be recognized.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="sound_file" required="true" />
|
||||
<parameter name="sound_file" required="true" argsep="&">
|
||||
<para>Ampersand separated list of filenames. If the filename
|
||||
is a relative filename (it does not begin with a slash), it
|
||||
will be searched for in the Asterisk sounds directory. If the
|
||||
filename is able to be parsed as a URL, Asterisk will
|
||||
download the file and then begin playback on it. To include a
|
||||
literal <literal>&</literal> in the URL you can enclose
|
||||
the URL in single quotes.</para>
|
||||
<argument name="sound_file" required="true" />
|
||||
<argument name="sound_file2" multiple="true" />
|
||||
</parameter>
|
||||
<parameter name="timeout">
|
||||
<para>Timeout integer in seconds. Note the timeout will only start
|
||||
once the sound file has stopped playing.</para>
|
||||
|
@ -95,6 +105,9 @@
|
|||
<option name="n">
|
||||
<para>Don't answer the channel if it has not already been answered.</para>
|
||||
</option>
|
||||
<option name="p">
|
||||
<para>Return partial results when backend is terminated by timeout.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
|
@ -690,10 +703,12 @@ static int speech_streamfile(struct ast_channel *chan, const char *filename, con
|
|||
|
||||
enum {
|
||||
SB_OPT_NOANSWER = (1 << 0),
|
||||
SB_OPT_PARTIALRESULTS = (1 << 1),
|
||||
};
|
||||
|
||||
AST_APP_OPTIONS(speech_background_options, BEGIN_OPTIONS
|
||||
AST_APP_OPTION('n', SB_OPT_NOANSWER),
|
||||
AST_APP_OPTION('p', SB_OPT_PARTIALRESULTS),
|
||||
END_OPTIONS );
|
||||
|
||||
/*! \brief SpeechBackground(Sound File,Timeout) Dialplan Application */
|
||||
|
@ -776,7 +791,10 @@ static int speech_background(struct ast_channel *chan, const char *data)
|
|||
/* Okay it's streaming so go into a loop grabbing frames! */
|
||||
while (done == 0) {
|
||||
/* If the filename is null and stream is not running, start up a new sound file */
|
||||
if (!quieted && (ast_channel_streamid(chan) == -1 && ast_channel_timingfunc(chan) == NULL) && (filename = strsep(&filename_tmp, "&"))) {
|
||||
if (!quieted
|
||||
&& ast_channel_streamid(chan) == -1
|
||||
&& ast_channel_timingfunc(chan) == NULL
|
||||
&& (filename = ast_strsep(&filename_tmp, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
|
||||
/* Discard old stream information */
|
||||
ast_stopstream(chan);
|
||||
/* Start new stream */
|
||||
|
@ -920,7 +938,10 @@ static int speech_background(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(dtmf)) {
|
||||
if (ast_strlen_zero(dtmf) && speech->state == AST_SPEECH_STATE_READY && ast_test_flag(&options, SB_OPT_PARTIALRESULTS)) {
|
||||
/* Copy to speech structure the results, even partial ones, if desired and available */
|
||||
speech->results = ast_speech_results_get(speech);
|
||||
} else if (!ast_strlen_zero(dtmf)) {
|
||||
/* We sort of make a results entry */
|
||||
speech->results = ast_calloc(1, sizeof(*speech->results));
|
||||
if (speech->results != NULL) {
|
||||
|
|
|
@ -1076,7 +1076,7 @@ static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_
|
|||
ast_channel_name(chan), app_gosub, sub_args,
|
||||
S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
|
||||
ast_log(LOG_WARNING, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
|
||||
ast_channel_name(chan), app_gosub, sub_args);
|
||||
balance_stack(chan);
|
||||
pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -120,6 +120,9 @@
|
|||
<configOption name="end_marked">
|
||||
<synopsis>Kick the user from the conference when the last marked user leaves</synopsis>
|
||||
</configOption>
|
||||
<configOption name="end_marked_any">
|
||||
<synopsis>Kick the user from the conference when any marked user leaves</synopsis>
|
||||
</configOption>
|
||||
<configOption name="talk_detection_events">
|
||||
<synopsis>Set whether or not notifications of when a user begins and ends talking should be sent out as events over AMI</synopsis>
|
||||
</configOption>
|
||||
|
@ -1440,10 +1443,7 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *
|
|||
|
||||
/* if adding any of the actions failed, bail */
|
||||
if (res) {
|
||||
struct conf_menu_action *menu_action;
|
||||
while ((menu_action = AST_LIST_REMOVE_HEAD(&menu_entry->actions, action))) {
|
||||
ast_free(menu_action);
|
||||
}
|
||||
conf_menu_entry_destroy(menu_entry);
|
||||
ast_free(menu_entry);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1452,6 +1452,7 @@ static int add_menu_entry(struct conf_menu *menu, const char *dtmf, const char *
|
|||
AST_LIST_TRAVERSE_SAFE_BEGIN(&menu->entries, cur, entry) {
|
||||
if (!strcasecmp(cur->dtmf, menu_entry->dtmf)) {
|
||||
AST_LIST_REMOVE_CURRENT(entry);
|
||||
conf_menu_entry_destroy(cur);
|
||||
ast_free(cur);
|
||||
break;
|
||||
}
|
||||
|
@ -1583,9 +1584,12 @@ static char *handle_cli_confbridge_show_user_profile(struct ast_cli_entry *e, in
|
|||
ast_cli(a->fd,"Wait Marked: %s\n",
|
||||
u_profile.flags & USER_OPT_WAITMARKED ?
|
||||
"enabled" : "disabled");
|
||||
ast_cli(a->fd,"END Marked: %s\n",
|
||||
ast_cli(a->fd,"END Marked (All): %s\n",
|
||||
u_profile.flags & USER_OPT_ENDMARKED ?
|
||||
"enabled" : "disabled");
|
||||
ast_cli(a->fd,"END Marked (Any): %s\n",
|
||||
u_profile.flags & USER_OPT_ENDMARKEDANY ?
|
||||
"enabled" : "disabled");
|
||||
ast_cli(a->fd,"Drop_silence: %s\n",
|
||||
u_profile.flags & USER_OPT_DROP_SILENCE ?
|
||||
"enabled" : "disabled");
|
||||
|
@ -2216,6 +2220,30 @@ static int user_template_handler(const struct aco_option *opt, struct ast_variab
|
|||
return conf_find_user_profile(NULL, var->value, u_profile) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sample_rate_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct bridge_profile *b_profile = obj;
|
||||
unsigned int *slot;
|
||||
|
||||
if (!strcasecmp(var->name, "internal_sample_rate")) {
|
||||
slot = &b_profile->internal_sample_rate;
|
||||
if (!strcasecmp(var->value, "auto")) {
|
||||
*slot = 0;
|
||||
return 0;
|
||||
}
|
||||
} else if (!strcasecmp(var->name, "maximum_sample_rate")) {
|
||||
slot = &b_profile->maximum_sample_rate;
|
||||
if (!strcasecmp(var->value, "none")) {
|
||||
*slot = 0;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ast_parse_arg(var->value, PARSE_UINT32 | PARSE_IN_RANGE, slot, 8000, 192000);
|
||||
}
|
||||
|
||||
static int bridge_template_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct bridge_profile *b_profile = obj;
|
||||
|
@ -2409,6 +2437,7 @@ int conf_load_config(void)
|
|||
aco_option_register(&cfg_info, "announce_only_user", ACO_EXACT, user_types, "yes", OPT_BOOLFLAG_T, 0, FLDSET(struct user_profile, flags), USER_OPT_NOONLYPERSON);
|
||||
aco_option_register(&cfg_info, "wait_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_WAITMARKED);
|
||||
aco_option_register(&cfg_info, "end_marked", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKED);
|
||||
aco_option_register(&cfg_info, "end_marked_any", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ENDMARKEDANY);
|
||||
aco_option_register(&cfg_info, "talk_detection_events", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_TALKER_DETECT);
|
||||
aco_option_register(&cfg_info, "dtmf_passthrough", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_DTMF_PASS);
|
||||
aco_option_register(&cfg_info, "announce_join_leave", ACO_EXACT, user_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct user_profile, flags), USER_OPT_ANNOUNCE_JOIN_LEAVE);
|
||||
|
@ -2432,10 +2461,9 @@ int conf_load_config(void)
|
|||
/* Bridge options */
|
||||
aco_option_register(&cfg_info, "type", ACO_EXACT, bridge_types, NULL, OPT_NOOP_T, 0, 0);
|
||||
aco_option_register(&cfg_info, "jitterbuffer", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), USER_OPT_JITTERBUFFER);
|
||||
/* "auto" will fail to parse as a uint, but we use PARSE_DEFAULT to set the value to 0 in that case, which is the value that auto resolves to */
|
||||
aco_option_register(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, internal_sample_rate), 0);
|
||||
aco_option_register_custom(&cfg_info, "internal_sample_rate", ACO_EXACT, bridge_types, "auto", sample_rate_handler, 0);
|
||||
aco_option_register(&cfg_info, "binaural_active", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_BINAURAL_ACTIVE);
|
||||
aco_option_register(&cfg_info, "maximum_sample_rate", ACO_EXACT, bridge_types, "0", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct bridge_profile, maximum_sample_rate), 0);
|
||||
aco_option_register_custom(&cfg_info, "maximum_sample_rate", ACO_EXACT, bridge_types, "none", sample_rate_handler, 0);
|
||||
aco_option_register_custom(&cfg_info, "mixing_interval", ACO_EXACT, bridge_types, "20", mix_interval_handler, 0);
|
||||
aco_option_register(&cfg_info, "record_conference", ACO_EXACT, bridge_types, "no", OPT_BOOLFLAG_T, 1, FLDSET(struct bridge_profile, flags), BRIDGE_OPT_RECORD_CONFERENCE);
|
||||
aco_option_register_custom(&cfg_info, "video_mode", ACO_EXACT, bridge_types, NULL, video_mode_handler, 0);
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
@ -85,37 +82,39 @@ static void leave_marked(struct confbridge_user *user)
|
|||
|
||||
conf_remove_user_marked(user->conference, user);
|
||||
|
||||
if (user->conference->markedusers == 0) {
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->active_list, user_iter, list) {
|
||||
/* Kick ENDMARKED cbu_iters */
|
||||
if (ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKED) && !user_iter->kicked) {
|
||||
if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
|
||||
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
|
||||
AST_LIST_REMOVE_CURRENT(list);
|
||||
user_iter->conference->activeusers--;
|
||||
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
|
||||
user_iter->conference->waitingusers++;
|
||||
}
|
||||
user_iter->kicked = 1;
|
||||
pbx_builtin_setvar_helper(user_iter->chan, "CONFBRIDGE_RESULT", "ENDMARKED");
|
||||
ast_bridge_remove(user_iter->conference->bridge, user_iter->chan);
|
||||
} else if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
|
||||
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
|
||||
need_prompt = 1;
|
||||
|
||||
/* If all marked users have left, or we're set to kick if any marked user leaves, then boot everyone */
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&user->conference->active_list, user_iter, list) {
|
||||
if (user->conference->markedusers > 0 && !ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY)) {
|
||||
continue;
|
||||
}
|
||||
/* Kick ENDMARKED cbu_iters */
|
||||
if ((ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKED) || ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY)) && !user_iter->kicked) {
|
||||
if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
|
||||
&& (!ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER) || ast_test_flag(&user_iter->u_profile, USER_OPT_ENDMARKEDANY))) {
|
||||
AST_LIST_REMOVE_CURRENT(list);
|
||||
user_iter->conference->activeusers--;
|
||||
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
|
||||
user_iter->conference->waitingusers++;
|
||||
} else {
|
||||
/* User is neither wait_marked nor end_marked; however, they
|
||||
* should still hear the prompt.
|
||||
*/
|
||||
need_prompt = 1;
|
||||
}
|
||||
user_iter->kicked = 1;
|
||||
pbx_builtin_setvar_helper(user_iter->chan, "CONFBRIDGE_RESULT", "ENDMARKED");
|
||||
ast_bridge_remove(user_iter->conference->bridge, user_iter->chan);
|
||||
} else if (ast_test_flag(&user_iter->u_profile, USER_OPT_WAITMARKED)
|
||||
&& !ast_test_flag(&user_iter->u_profile, USER_OPT_MARKEDUSER)) {
|
||||
need_prompt = 1;
|
||||
|
||||
AST_LIST_REMOVE_CURRENT(list);
|
||||
user_iter->conference->activeusers--;
|
||||
AST_LIST_INSERT_TAIL(&user_iter->conference->waiting_list, user_iter, list);
|
||||
user_iter->conference->waitingusers++;
|
||||
} else {
|
||||
/* User is neither wait_marked nor end_marked nor end_marked_any; however, they
|
||||
* should still hear the prompt.
|
||||
*/
|
||||
need_prompt = 1;
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
|
||||
switch (user->conference->activeusers) {
|
||||
case 0:
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*
|
||||
* Please follow coding guidelines
|
||||
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
|
@ -25,7 +22,7 @@
|
|||
*
|
||||
* \author\verbatim Terry Wilson <twilson@digium.com> \endverbatim
|
||||
*
|
||||
* See https://wiki.asterisk.org/wiki/display/AST/Confbridge+state+changes for
|
||||
* See https://docs.asterisk.org/Development/Reference-Information/Other-Reference-Information/Confbridge-state-changes/ for
|
||||
* a more complete description of how conference states work.
|
||||
*/
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ enum user_profile_flags {
|
|||
USER_OPT_TEXT_MESSAGING = (1 << 19), /*!< Send text messages to the user */
|
||||
USER_OPT_ANSWER_CHANNEL = (1 << 20), /*!< Sets if the channel should be answered if currently unanswered */
|
||||
USER_OPT_HEAR_OWN_JOIN_SOUND = (1 << 21), /*!< Set if the caller should hear the join sound */
|
||||
USER_OPT_ENDMARKEDANY = (1 << 22), /*!< Set if the user should be kicked after any marked user exits */
|
||||
};
|
||||
|
||||
enum bridge_profile_flags {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
|
@ -14,20 +14,24 @@
|
|||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
|
||||
# needed for multi-threaded programs (defaults to the value of CC
|
||||
# respectively CXX otherwise). (This is necessary on e.g. AIX to use the
|
||||
# special cc_r/CC_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
# CXX="$PTHREAD_CXX"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
|
@ -55,6 +59,7 @@
|
|||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
# Copyright (c) 2019 Marc Stevens <marc.stevens@cwi.nl>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
|
@ -67,7 +72,7 @@
|
|||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
|
@ -82,7 +87,7 @@
|
|||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 23
|
||||
#serial 31
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
|
@ -104,6 +109,7 @@ if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
|||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
|
@ -123,10 +129,12 @@ fi
|
|||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
# Create a list of thread flags to try. Items with a "," contain both
|
||||
# C compiler flags (before ",") and linker flags (after ","). Other items
|
||||
# starting with a "-" are C compiler flags, and remaining items are
|
||||
# library names, except for "none" which indicates that we try without
|
||||
# any flags at all, and "pthread-config" which is a program returning
|
||||
# the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
|
@ -194,14 +202,47 @@ case $host_os in
|
|||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
|
||||
ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
# Note that for GCC and Clang -pthread generally implies -lpthread,
|
||||
# except when -nostdlib is passed.
|
||||
# This is problematic using libtool to build C++ shared libraries with pthread:
|
||||
# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
|
||||
# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
|
||||
# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
|
||||
# To solve this, first try -pthread together with -lpthread for GCC
|
||||
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
|
||||
|
||||
AS_IF([test "x$ax_pthread_clang" = "xyes"],
|
||||
[ax_pthread_flags="-pthread,-lpthread -pthread"])
|
||||
|
||||
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
|
@ -224,101 +265,6 @@ AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
|||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
ax_pthread_clang_warning=no
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
PTHREAD_CFLAGS="-pthread"
|
||||
PTHREAD_LIBS=
|
||||
|
||||
ax_pthread_ok=yes
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
@ -328,10 +274,10 @@ for ax_pthread_try_flag in $ax_pthread_flags; do
|
|||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-mt,pthread)
|
||||
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
|
||||
PTHREAD_CFLAGS="-mt"
|
||||
PTHREAD_LIBS="-lpthread"
|
||||
*,*)
|
||||
PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
|
||||
PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
|
||||
AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
|
||||
;;
|
||||
|
||||
-*)
|
||||
|
@ -371,7 +317,13 @@ for ax_pthread_try_flag in $ax_pthread_flags; do
|
|||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *some_global = NULL;
|
||||
static void routine(void *a)
|
||||
{
|
||||
/* To avoid any unused-parameter or
|
||||
unused-but-set-parameter warning. */
|
||||
some_global = a;
|
||||
}
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
|
@ -393,6 +345,80 @@ for ax_pthread_try_flag in $ax_pthread_flags; do
|
|||
done
|
||||
fi
|
||||
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
|
@ -438,7 +464,8 @@ if test "x$ax_pthread_ok" = "xyes"; then
|
|||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;
|
||||
return i;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
|
@ -460,18 +487,28 @@ if test "x$ax_pthread_ok" = "xyes"; then
|
|||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
[
|
||||
AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
|
||||
AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
|
||||
],
|
||||
[
|
||||
AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
|
||||
AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
|
||||
]
|
||||
)
|
||||
])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
AC_SUBST([PTHREAD_CXX])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
|
|
|
@ -9,9 +9,9 @@ check_for_app() {
|
|||
fi
|
||||
}
|
||||
|
||||
# OpenBSD: pkg_add autoconf%2.63 automake%1.9 metaauto
|
||||
test -n "$AUTOCONF_VERSION" || export AUTOCONF_VERSION=2.63
|
||||
test -n "$AUTOMAKE_VERSION" || export AUTOMAKE_VERSION=1.9
|
||||
# OpenBSD: pkg_add autoconf%2.69 automake%1.16 metaauto
|
||||
test -n "$AUTOCONF_VERSION" || export AUTOCONF_VERSION=2.69
|
||||
test -n "$AUTOMAKE_VERSION" || export AUTOMAKE_VERSION=1.16
|
||||
|
||||
check_for_app autoconf
|
||||
check_for_app autoheader
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "asterisk/mixmonitor.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/beep.h"
|
||||
|
||||
enum set_touch_variables_res {
|
||||
SET_TOUCH_SUCCESS,
|
||||
|
@ -78,12 +79,13 @@ static void set_touch_variable(enum set_touch_variables_res *res, struct ast_cha
|
|||
}
|
||||
}
|
||||
|
||||
static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
|
||||
static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix, char **touch_monitor_beep)
|
||||
{
|
||||
enum set_touch_variables_res res = SET_TOUCH_UNSET;
|
||||
const char *var_format;
|
||||
const char *var_monitor;
|
||||
const char *var_prefix;
|
||||
const char *var_beep;
|
||||
|
||||
SCOPED_CHANNELLOCK(lock, chan);
|
||||
|
||||
|
@ -91,14 +93,17 @@ static enum set_touch_variables_res set_touch_variables(struct ast_channel *chan
|
|||
var_format = "TOUCH_MIXMONITOR_FORMAT";
|
||||
var_monitor = "TOUCH_MIXMONITOR";
|
||||
var_prefix = "TOUCH_MIXMONITOR_PREFIX";
|
||||
var_beep = "TOUCH_MIXMONITOR_BEEP";
|
||||
} else {
|
||||
var_format = "TOUCH_MONITOR_FORMAT";
|
||||
var_monitor = "TOUCH_MONITOR";
|
||||
var_prefix = "TOUCH_MONITOR_PREFIX";
|
||||
var_beep = "TOUCH_MONITOR_BEEP";
|
||||
}
|
||||
set_touch_variable(&res, chan, var_format, touch_format);
|
||||
set_touch_variable(&res, chan, var_monitor, touch_monitor);
|
||||
set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
|
||||
set_touch_variable(&res, chan, var_beep, touch_monitor_beep);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -141,20 +146,22 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct
|
|||
char *touch_filename;
|
||||
size_t len;
|
||||
int x;
|
||||
char beep_id[64] = "";
|
||||
enum set_touch_variables_res set_touch_res;
|
||||
|
||||
RAII_VAR(char *, touch_format, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_beep, NULL, ast_free);
|
||||
|
||||
set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
|
||||
&touch_monitor, &touch_monitor_prefix);
|
||||
&touch_monitor, &touch_monitor_prefix, &touch_monitor_beep);
|
||||
switch (set_touch_res) {
|
||||
case SET_TOUCH_SUCCESS:
|
||||
break;
|
||||
case SET_TOUCH_UNSET:
|
||||
set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
|
||||
&touch_monitor_prefix);
|
||||
&touch_monitor_prefix, &touch_monitor_beep);
|
||||
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
@ -195,7 +202,28 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct
|
|||
|
||||
ast_verb(4, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
|
||||
|
||||
if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, NULL)) {
|
||||
if (!ast_strlen_zero(touch_monitor_beep)) {
|
||||
unsigned int interval = 15;
|
||||
if (sscanf(touch_monitor_beep, "%30u", &interval) != 1) {
|
||||
ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
|
||||
if (interval > 0) {
|
||||
if (interval < 5) {
|
||||
interval = 5;
|
||||
ast_log(LOG_WARNING, "Interval '%s' too small for periodic beep. Using minimum of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
|
||||
if (ast_beep_start(peer_chan, interval, beep_id, sizeof(beep_id))) {
|
||||
ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT, beep_id)) {
|
||||
ast_verb(4, "AutoMonitor feature was tried by '%s' but monitor failed to start.\n",
|
||||
ast_channel_name(bridge_channel->chan));
|
||||
return;
|
||||
|
@ -322,7 +350,7 @@ static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struc
|
|||
|
||||
static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
|
||||
{
|
||||
char *touch_filename;
|
||||
char *touch_filename, mix_options[32] = "b";
|
||||
size_t len;
|
||||
int x;
|
||||
enum set_touch_variables_res set_touch_res;
|
||||
|
@ -330,15 +358,16 @@ static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, stru
|
|||
RAII_VAR(char *, touch_format, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||
RAII_VAR(char *, touch_monitor_beep, NULL, ast_free);
|
||||
|
||||
set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
|
||||
&touch_monitor, &touch_monitor_prefix);
|
||||
&touch_monitor, &touch_monitor_prefix, &touch_monitor_beep);
|
||||
switch (set_touch_res) {
|
||||
case SET_TOUCH_SUCCESS:
|
||||
break;
|
||||
case SET_TOUCH_UNSET:
|
||||
set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
|
||||
&touch_monitor_prefix);
|
||||
&touch_monitor_prefix, &touch_monitor_beep);
|
||||
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
@ -381,7 +410,22 @@ static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, stru
|
|||
|
||||
ast_verb(4, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
|
||||
|
||||
if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
|
||||
if (!ast_strlen_zero(touch_monitor_beep)) {
|
||||
unsigned int interval = 15;
|
||||
if (sscanf(touch_monitor_beep, "%30u", &interval) != 1) {
|
||||
ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
|
||||
if (interval < 5) {
|
||||
interval = 5;
|
||||
ast_log(LOG_WARNING, "Interval '%s' too small for periodic beep. Using minimum of %u\n",
|
||||
touch_monitor_beep, interval);
|
||||
}
|
||||
snprintf(mix_options, sizeof(mix_options), "bB(%d)", interval);
|
||||
}
|
||||
|
||||
if (ast_start_mixmonitor(peer_chan, touch_filename, mix_options)) {
|
||||
ast_verb(4, "AutoMixMonitor feature was tried by '%s' but MixMonitor failed to start.\n",
|
||||
ast_channel_name(bridge_channel->chan));
|
||||
|
||||
|
|
|
@ -181,7 +181,14 @@ static int simple_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chann
|
|||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
|
||||
if (!ast_stream_topology_equal(new_top, existing_top)) {
|
||||
ast_channel_request_stream_topology_change(c1, new_top, &simple_bridge);
|
||||
} else {
|
||||
ast_debug(3, "%s: Topologies already match. Current: %s Requested: %s\n",
|
||||
ast_channel_name(c1),
|
||||
ast_str_tmp(256, ast_stream_topology_to_str(existing_top, &STR_TMP)),
|
||||
ast_str_tmp(256, ast_stream_topology_to_str(new_top, &STR_TMP)));
|
||||
}
|
||||
ast_stream_topology_free(new_top);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<support_level>extended</support_level>
|
||||
</member>
|
||||
<member name="DETECT_DEADLOCKS" displayname="Detect Deadlocks">
|
||||
<depend>DEBUG_THREADS</depend>
|
||||
<support_level>extended</support_level>
|
||||
</member>
|
||||
<member name="DUMP_SCHEDULER" displayname="Dump Scheduler Contents for Debugging">
|
||||
|
|
|
@ -128,4 +128,8 @@
|
|||
<defaultenabled>yes</defaultenabled>
|
||||
<depend>native_arch</depend>
|
||||
</member>
|
||||
<member name="ADD_CFLAGS_TO_BUILDOPTS_H" displayname="Add ALL of the flags on this page to buildopts.h. Useful for IDEs but may cause slightly longer compile times after flags are changed.">
|
||||
<support_level>core</support_level>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
</member>
|
||||
</category>
|
||||
|
|
|
@ -58,7 +58,7 @@ if [[ -z ${cache_dir} ]] ; then
|
|||
fi
|
||||
|
||||
version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
|
||||
if [[ ! ${version} =~ ^(GIT-)?(certified/)?([^.-]+)[.-].* ]] ; then
|
||||
if [[ ! ${version} =~ ^(GIT-)?(certified[/-])?([^.-]+)[.-].* ]] ; then
|
||||
echo "${module_name}: Couldn't parse version ${version}"
|
||||
exit 1
|
||||
fi
|
||||
|
@ -172,7 +172,7 @@ if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then
|
|||
|
||||
cs=$(${MD5} ${f} | cut -b1-32)
|
||||
if [[ "${cs}" != "${sum}" ]] ; then
|
||||
echo Checksum mismatch: ${f}
|
||||
echo "Checksum mismatch: ${f}"
|
||||
need_install=1
|
||||
break
|
||||
fi
|
||||
|
@ -194,8 +194,8 @@ else
|
|||
fi
|
||||
|
||||
need_download=1
|
||||
if [[ -f ${cache_dir}/${full_name}.manifest.xml ]] ; then
|
||||
cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${full_name}.manifest.xml)
|
||||
if [[ -f ${cache_dir}/${full_name}-${major_version}.manifest.xml ]] ; then
|
||||
cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${full_name}-${major_version}.manifest.xml)
|
||||
cpvi=$(version_convert ${cpv})
|
||||
echo "${full_name}: Cached package version ${cpv} (${cpvi})"
|
||||
if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then
|
||||
|
@ -210,7 +210,7 @@ if [[ ${need_download} = 1 ]] ; then
|
|||
echo "${full_name}: Unable to fetch ${remote_url}/${tarball}"
|
||||
exit 1
|
||||
}
|
||||
cp ${tmpdir}/${variant_manifest} ${cache_dir}/${full_name}.manifest.xml
|
||||
cp ${tmpdir}/${variant_manifest} ${cache_dir}/${full_name}-${major_version}.manifest.xml
|
||||
fi
|
||||
|
||||
tar -xzf ${cache_dir}/${tarball} -C ${cache_dir}
|
||||
|
|
|
@ -18,42 +18,79 @@ then
|
|||
# gets added to BUILDOPTS.
|
||||
fi
|
||||
|
||||
TMP=`${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
|
||||
for x in ${TMP}; do
|
||||
if test "${x}" = "AO2_DEBUG" \
|
||||
-o "${x}" = "BETTER_BACKTRACES" \
|
||||
-o "${x}" = "BUILD_NATIVE" \
|
||||
-o "${x}" = "COMPILE_DOUBLE" \
|
||||
-o "${x}" = "DEBUG_CHAOS" \
|
||||
-o "${x}" = "DEBUG_SCHEDULER" \
|
||||
-o "${x}" = "DETECT_DEADLOCKS" \
|
||||
-o "${x}" = "DONT_OPTIMIZE" \
|
||||
-o "${x}" = "DUMP_SCHEDULER" \
|
||||
-o "${x}" = "LOTS_OF_SPANS" \
|
||||
-o "${x}" = "MALLOC_DEBUG" \
|
||||
-o "${x}" = "RADIO_RELAX" \
|
||||
-o "${x}" = "REBUILD_PARSERS" \
|
||||
-o "${x}" = "REF_DEBUG" \
|
||||
-o "${x}" = "USE_HOARD_ALLOCATOR" ; then
|
||||
# These options are only for specific sources and have no effect on public ABI.
|
||||
# Keep them out of buildopts.h so ccache does not invalidate all sources.
|
||||
continue
|
||||
fi
|
||||
ADD_CFLAGS_TO_BUILDOPTS=false
|
||||
MENUSELECT_CFLAGS=$(${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts)
|
||||
echo "$MENUSELECT_CFLAGS" | grep -q -e "ADD_CFLAGS_TO_BUILDOPTS_H" && ADD_CFLAGS_TO_BUILDOPTS=true
|
||||
|
||||
# Clean up MENUSELECT_CFLAGS by removing the "MENUSELECT_CFLAGS="
|
||||
# at the front, the "ADD_CFLAGS_TO_BUILDOPTS_H" flag, and any "-D"
|
||||
# entries.
|
||||
MENUSELECT_CFLAGS=$( echo "$MENUSELECT_CFLAGS" | \
|
||||
sed -r -e "s/(MENUSELECT_CFLAGS=|ADD_CFLAGS_TO_BUILDOPTS_H|-D)//g")
|
||||
|
||||
# This is a list of flags that don't affect the ABI.
|
||||
# "ADD_CFLAGS_TO_BUILDOPTS_H" is NOT set, we'll filter these
|
||||
# out of the buildopts.h file.
|
||||
#
|
||||
# These used to always be filtered out but if they're not in
|
||||
# buildopts.h, many IDEs will show them as undefined and mark
|
||||
# any code blocks enabled by them as disabled.
|
||||
#
|
||||
# The original reasoning for removing them was that trivial
|
||||
# changes to the buildopts.h file will cause ccache to
|
||||
# invalidate any source files that use it and increase the
|
||||
# compile time. It's not such a huge deal these days but
|
||||
# to preserve backwards behavior the default is still to
|
||||
# remove them.
|
||||
#
|
||||
# The ABI-breaking flags are always included in buildopts.h.
|
||||
|
||||
# This variable is used by sed so it needs to be a valid
|
||||
# regex which will be surrounded by parens.]
|
||||
FILTER_OUT="\
|
||||
AO2_DEBUG|BETTER_BACKTRACES|BUILD_NATIVE|\
|
||||
COMPILE_DOUBLE|DEBUG_CHAOS|DEBUG_SCHEDULER|\
|
||||
DETECT_DEADLOCKS|DONT_OPTIMIZE|DUMP_SCHEDULER|\
|
||||
LOTS_OF_SPANS|MALLOC_DEBUG|RADIO_RELAX|\
|
||||
REBUILD_PARSERS|REF_DEBUG|USE_HOARD_ALLOCATOR"
|
||||
|
||||
# Create buildopts.h
|
||||
|
||||
INCLUDE_CFLAGS="$MENUSELECT_CFLAGS"
|
||||
# Do the filter-out if needed.
|
||||
if ! $ADD_CFLAGS_TO_BUILDOPTS ; then
|
||||
INCLUDE_CFLAGS=$( echo "$MENUSELECT_CFLAGS" | \
|
||||
sed -r -e "s/(${FILTER_OUT})//g")
|
||||
fi
|
||||
|
||||
# Output the defines.
|
||||
for x in ${INCLUDE_CFLAGS}; do
|
||||
echo "#define ${x} 1"
|
||||
if test "${x}" = "LOW_MEMORY" ; then
|
||||
# LOW_MEMORY isn't an ABI affecting option but it is used in many sources
|
||||
# so it gets defined globally but is not included in AST_BUILTOPTS.
|
||||
continue
|
||||
fi
|
||||
if test "x${BUILDOPTS}" != "x" ; then
|
||||
BUILDOPTS="${BUILDOPTS}, ${x}"
|
||||
else
|
||||
BUILDOPTS="${x}"
|
||||
fi
|
||||
done
|
||||
|
||||
BUILDSUM=`echo ${BUILDOPTS} | ${MD5} | cut -c1-32`
|
||||
# We NEVER include the non-ABI-breaking flags in the
|
||||
# BUILDOPTS or use them to calculate the checksum so
|
||||
# we always filter out any that may exist.
|
||||
# After the filter-out, we also need to convert the
|
||||
# possibly-multi-spaced MENUSELECT_CFLAGS to a nice
|
||||
# comma-separated list.
|
||||
# I.E.
|
||||
# Remove leading spaces.
|
||||
# Convert consecutive interior spaces to a single space.
|
||||
# Remove trailing spaces.
|
||||
# Convert the now-single-spaces in the interior to ", ".
|
||||
BUILDOPTS=$( echo "$MENUSELECT_CFLAGS" | \
|
||||
sed -r -e "s/(${FILTER_OUT}|LOW_MEMORY)//g" -e "s/^\s+//g;s/\s+/ /g;s/\s+$//g;s/\s/, /g" )
|
||||
|
||||
# Calculate the checksum on only the ABI-breaking flags.
|
||||
BUILDSUM=$(echo "${BUILDOPTS}" | ${MD5} | cut -c1-32)
|
||||
|
||||
echo "#define AST_BUILDOPT_SUM \"${BUILDSUM}\""
|
||||
echo "#define AST_BUILDOPTS \"${BUILDOPTS}\""
|
||||
|
||||
# However, it'd be nice to see the non-ABI-breaking flags
|
||||
# when you do a "core show settings" so we create a separate
|
||||
# define for them.
|
||||
BUILDOPTS_ALL=$( echo "$MENUSELECT_CFLAGS" | \
|
||||
sed -r -e "s/^\s+//g;s/\s+/ /g;s/\s+$//g;s/\s/, /g" )
|
||||
echo "#define AST_BUILDOPTS_ALL \"${BUILDOPTS_ALL}\""
|
||||
|
|
|
@ -1,220 +1,67 @@
|
|||
#!/bin/sh
|
||||
|
||||
AWK=${AWK:-awk}
|
||||
GIT=${GIT:-git}
|
||||
GREP=${GREP:-grep}
|
||||
SED=${SED:-sed}
|
||||
|
||||
AWK=${AWK:-awk}
|
||||
|
||||
if [ -f ${1}/.version ]; then
|
||||
cat ${1}/.version
|
||||
elif [ -d ${1}/.svn ]; then
|
||||
PARTS=`LANG=C svn info ${1} | ${GREP} URL | ${AWK} '{print $2;}' | ${SED} -e 's:^.*/svn/asterisk/::' | ${SED} -e 's:/: :g'`
|
||||
BRANCH=0
|
||||
TEAM=0
|
||||
TAG=0
|
||||
FEATURE=0
|
||||
|
||||
REV=`svnversion -c ${1} | cut -d: -f2`
|
||||
|
||||
INTEGRATED=`LANG=C svn pg automerge-propname ${1}`
|
||||
if [ -z "${INTEGRATED}" ] ; then
|
||||
INTEGRATED=svnmerge-integrated
|
||||
fi
|
||||
|
||||
BASE=`LANG=C svn pg ${INTEGRATED} ${1} | cut -d: -f1`
|
||||
|
||||
if [ "${PARTS}" = "trunk" ] ; then
|
||||
echo SVN-trunk-r${REV}
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for PART in $PARTS ; do
|
||||
if [ ${TAG} != 0 ] ; then
|
||||
if [ "${PART}" = "autotag_for_be" ] ; then
|
||||
continue
|
||||
fi
|
||||
if [ "${PART}" = "autotag_for_sx00i" ] ; then
|
||||
continue
|
||||
fi
|
||||
RESULT="${PART}"
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ${BRANCH} != 0 ] ; then
|
||||
RESULT="${RESULT}-${PART}"
|
||||
if [ ${FEATURE} != 0 ] ; then
|
||||
RESULT="${RESULT}-${FEATURE_NAME}"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ${TEAM} != 0 ] ; then
|
||||
if [ -z "${RESULT}" ] ; then
|
||||
RESULT="${PART}"
|
||||
else
|
||||
RESULT="${RESULT}-${PART}"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "certified" ] ; then
|
||||
FEATURE=1
|
||||
FEATURE_NAME="cert"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "branches" ] ; then
|
||||
BRANCH=1
|
||||
RESULT="branch"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "tags" ] ; then
|
||||
TAG=1
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "team" ] ; then
|
||||
TEAM=1
|
||||
continue
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${TAG} != 0 ] ; then
|
||||
echo ${RESULT}
|
||||
else
|
||||
echo SVN-${RESULT}-r${REV}${BASE:+-${BASE}}
|
||||
fi
|
||||
elif [ -d ${1}/.git ]; then
|
||||
if [ -z ${GIT} ]; then
|
||||
GIT="git"
|
||||
fi
|
||||
|
||||
if ! command -v ${GIT} >/dev/null 2>&1; then
|
||||
echo "UNKNOWN__and_probably_unsupported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GITCHECK=$(${GIT} describe --always 2>/dev/null || echo gitfail 2>/dev/null)
|
||||
if [ "x${GITCHECK}" = "xgitfail" ]; then
|
||||
echo "UNKNOWN__git_check_fail"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ${1}
|
||||
|
||||
# If the first log commit messages indicates that this is checked into
|
||||
# subversion, we'll just use the SVN- form of the revision.
|
||||
MODIFIED=""
|
||||
SVN_REV=`${GIT} log --pretty=full -1 | ${SED} -n '/git-svn-id:/ s/.*\@\([^ ]*\) .*/\1/p'`
|
||||
if [ -z "$SVN_REV" ]; then
|
||||
# If MAINLINE_BRANCH is already set in the environment, use it.
|
||||
if [ -z "${MAINLINE_BRANCH}" ] ; then
|
||||
# Try to retrieve MAINLINE_BRANCH from a local .develvars file first.
|
||||
# .develvars is keyed by the branch name so we need to get that first.
|
||||
BRANCH=$(${GIT} symbolic-ref --short HEAD)
|
||||
if [ -f .develvars ] ; then
|
||||
MAINLINE_BRANCH=$(${GIT} config -f .develvars --get branch.${BRANCH}.mainline-branch)
|
||||
fi
|
||||
|
||||
# If we didn't find it, see if this is a well-known development branch.
|
||||
# development/<mainline_branch>/<branchname> or
|
||||
# devel/<mainline_branch>/<branchname>
|
||||
if [ "x${MAINLINE_BRANCH}" = "x" ] ; then
|
||||
MAINLINE_BRANCH=$(echo "${BRANCH}" | ${SED} -n -r -e "s@devel(opment)?/([0-9]+)/.+@\2@p")
|
||||
fi
|
||||
|
||||
# If we didn't find it, get it from .gitreview defaultbranch.
|
||||
if [ "x${MAINLINE_BRANCH}" = "x" ] ; then
|
||||
MAINLINE_BRANCH=$(${GIT} config -f .gitreview --get gerrit.defaultbranch)
|
||||
fi
|
||||
fi
|
||||
|
||||
VERSION=`${GIT} describe --long --always --tags --dirty=M 2> /dev/null`
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ "`${GIT} ls-files -m | wc -l`" != "0" ]; then
|
||||
MODIFIED="M"
|
||||
fi
|
||||
# Some older versions of git do not support all the above
|
||||
# options.
|
||||
VERSION=`${GIT} rev-parse --short --verify HEAD`${MODIFIED}
|
||||
fi
|
||||
echo GIT-${MAINLINE_BRANCH}-${VERSION}
|
||||
else
|
||||
PARTS=`LANG=C ${GIT} log --pretty=full | ${GREP} -F "git-svn-id:" | head -1 | ${AWK} '{print $2;}' | ${SED} -e s:^.*/svn/$2/:: | ${SED} -e 's:/: :g' | ${SED} -e 's/@.*$//g'`
|
||||
BRANCH=0
|
||||
TEAM=0
|
||||
TAG=0
|
||||
FEATURE=0
|
||||
|
||||
if [ "`${GIT} ls-files -m | wc -l`" != "0" ]; then
|
||||
MODIFIED="M"
|
||||
fi
|
||||
|
||||
for PART in $PARTS ; do
|
||||
if [ ${TAG} != 0 ] ; then
|
||||
if [ "${PART}" = "autotag_for_be" ] ; then
|
||||
continue
|
||||
fi
|
||||
if [ "${PART}" = "autotag_for_sx00i" ] ; then
|
||||
continue
|
||||
fi
|
||||
RESULT="${PART}"
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ${BRANCH} != 0 ] ; then
|
||||
RESULT="${RESULT}-${PART}"
|
||||
if [ ${FEATURE} != 0 ] ; then
|
||||
RESULT="${RESULT}-${FEATURE_NAME}"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
|
||||
if [ ${TEAM} != 0 ] ; then
|
||||
if [ -z "${RESULT}" ] ; then
|
||||
RESULT="${PART}"
|
||||
else
|
||||
RESULT="${RESULT}-${PART}"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "certified" ] ; then
|
||||
FEATURE=1
|
||||
FEATURE_NAME="cert"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "branches" ] ; then
|
||||
BRANCH=1
|
||||
RESULT="branch"
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "tags" ] ; then
|
||||
TAG=1
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "team" ] ; then
|
||||
TEAM=1
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "${PART}" = "trunk" ]; then
|
||||
echo SVN-trunk-r${SVN_REV}${MODIFIED}
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${TAG} != 0 ] ; then
|
||||
echo ${RESULT}
|
||||
else
|
||||
echo SVN-${RESULT##-}-r${SVN_REV}${MODIFIED}
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "UNKNOWN__and_probably_unsupported"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -d ${1}/.git ]; then
|
||||
echo "UNKNOWN__and_probably_unsupported"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z ${GIT} ]; then
|
||||
GIT="git"
|
||||
fi
|
||||
|
||||
if ! command -v ${GIT} >/dev/null 2>&1; then
|
||||
echo "UNKNOWN__and_probably_unsupported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GITCHECK=$(${GIT} describe --always 2>/dev/null || echo gitfail 2>/dev/null)
|
||||
if [ "x${GITCHECK}" = "xgitfail" ]; then
|
||||
echo "UNKNOWN__git_check_fail"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ${1} || exit 1
|
||||
|
||||
MODIFIED=""
|
||||
|
||||
# If MAINLINE_BRANCH is already set in the environment, use it.
|
||||
if [ -z "${MAINLINE_BRANCH}" ] ; then
|
||||
# Try to retrieve MAINLINE_BRANCH from a local .develvars file first.
|
||||
# .develvars is keyed by the branch name so we need to get that first.
|
||||
BRANCH=$(${GIT} symbolic-ref --short HEAD 2>/dev/null)
|
||||
if [ -f .develvars ] ; then
|
||||
MAINLINE_BRANCH=$(${GIT} config -f .develvars --get branch.${BRANCH}.mainline-branch)
|
||||
fi
|
||||
|
||||
# If we didn't find it, see if this is a well-known development branch.
|
||||
# development/<mainline_branch>/<branchname> or
|
||||
# devel/<mainline_branch>/<branchname>
|
||||
if [ "x${MAINLINE_BRANCH}" = "x" ] ; then
|
||||
MAINLINE_BRANCH=$(echo "${BRANCH}" | ${SED} -n -r -e "s@devel(opment)?/([0-9]+)/.+@\2@p")
|
||||
fi
|
||||
|
||||
# If we didn't find it, get it from configure.ac.
|
||||
if [ "x${MAINLINE_BRANCH}" = "x" ] ; then
|
||||
MAINLINE_BRANCH=$(${AWK} '/AC_INIT/ { print substr($2, 2, length($2) - 3) }' configure.ac)
|
||||
fi
|
||||
fi
|
||||
|
||||
VERSION=`${GIT} describe --long --always --tags --dirty=M 2> /dev/null`
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ "`${GIT} ls-files -m | wc -l`" != "0" ]; then
|
||||
MODIFIED="M"
|
||||
fi
|
||||
# Some older versions of git do not support all the above
|
||||
# options.
|
||||
VERSION=`${GIT} rev-parse --short --verify HEAD`${MODIFIED}
|
||||
fi
|
||||
echo GIT-${MAINLINE_BRANCH}-${VERSION}
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
GREP=${GREP:-grep}
|
||||
|
||||
if test ! -f include/asterisk/buildopts.h ; then
|
||||
echo "include/asterisk/buildopts.h is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -f .flavor ; then
|
||||
EXTRA=""
|
||||
elif test ! -f .version ; then
|
||||
|
@ -18,14 +23,11 @@ then
|
|||
BUILDOPTS="AST_DEVMODE"
|
||||
fi
|
||||
|
||||
TMP=`${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
|
||||
for x in ${TMP}; do
|
||||
if test "x${BUILDOPTS}" != "x" ; then
|
||||
BUILDOPTS="${BUILDOPTS}, ${x}"
|
||||
else
|
||||
BUILDOPTS="${x}"
|
||||
fi
|
||||
done
|
||||
BUILDOPTS=$(sed -n -r -e 's/#define\s+AST_BUILDOPTS\s+"([^"]+)"/\1/gp' \
|
||||
include/asterisk/buildopts.h )
|
||||
|
||||
BUILDOPTS_ALL=$(sed -n -r -e 's/#define\s+AST_BUILDOPTS_ALL\s+"([^"]+)"/\1/gp' \
|
||||
include/asterisk/buildopts.h )
|
||||
|
||||
cat << END
|
||||
/*
|
||||
|
@ -43,6 +45,8 @@ static const char asterisk_version_num[] = "${ASTERISKVERSIONNUM}";
|
|||
|
||||
static const char asterisk_build_opts[] = "${BUILDOPTS}";
|
||||
|
||||
static const char asterisk_build_opts_all[] = "${BUILDOPTS_ALL}";
|
||||
|
||||
const char *ast_get_version(void)
|
||||
{
|
||||
return asterisk_version;
|
||||
|
@ -58,4 +62,9 @@ const char *ast_get_build_opts(void)
|
|||
return asterisk_build_opts;
|
||||
}
|
||||
|
||||
const char *ast_get_build_opts_all(void)
|
||||
{
|
||||
return asterisk_build_opts_all;
|
||||
}
|
||||
|
||||
END
|
||||
|
|
|
@ -135,12 +135,18 @@ if [ "${for_wiki}" -eq "1" ] || [ "${validate}" -eq "1" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
make_absolute() {
|
||||
case "$1" in
|
||||
/*) echo "$1" ;;
|
||||
*) echo "$source_tree/$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ "${command}" = "print_dependencies" ] ; then
|
||||
for subdir in ${mod_subdirs} ; do
|
||||
subpath="${source_tree}/${subdir}"
|
||||
# We WANT word splitting in the following line.
|
||||
# shellcheck disable=SC2046
|
||||
${GREP} -l -E '(language="en_US"|appdocsxml.dtd)' $(${FIND} "${subpath}" -name '*.c' -or -name '*.cc' -or -name '*.xml') || :
|
||||
subpath=$(make_absolute "$subdir")
|
||||
${FIND} "${subpath}" \( -name '*.c' -o -name '*.cc' -o -name '*.xml' \) \
|
||||
-exec ${GREP} -l -E '(language="en_US"|appdocsxml.dtd)' '{}' \;
|
||||
done
|
||||
exit
|
||||
fi
|
||||
|
@ -186,7 +192,7 @@ printf "Building Documentation For: "
|
|||
|
||||
for subdir in ${mod_subdirs} ; do
|
||||
printf "%s " "${subdir}"
|
||||
subdir_path="${source_tree}/${subdir}"
|
||||
subdir_path=$(make_absolute "$subdir")
|
||||
for i in $(${FIND} "${subdir_path}" -name '*.c' -or -name '*.cc'); do
|
||||
if [ "${with_moduleinfo}" -eq "1" ] ; then
|
||||
MODULEINFO=$(${AWK} -f "${source_tree}/build_tools/get_moduleinfo" "${i}")
|
||||
|
|
|
@ -29,6 +29,7 @@ URIPARSER=@PBX_URIPARSER@
|
|||
KQUEUE=@PBX_KQUEUE@
|
||||
LDAP=@PBX_LDAP@
|
||||
LIBEDIT=@PBX_LIBEDIT@
|
||||
LIBJWT=@PBX_LIBJWT@
|
||||
LIBXML2=@PBX_LIBXML2@
|
||||
LIBXSLT=@PBX_LIBXSLT@
|
||||
XMLSTARLET=@PBX_XMLSTARLET@
|
||||
|
|
|
@ -154,6 +154,8 @@ static struct console_pvt {
|
|||
struct ast_frame fr;
|
||||
/*! Running = 1, Not running = 0 */
|
||||
unsigned int streamstate:1;
|
||||
/*! Abort stream processing? */
|
||||
unsigned int abort:1;
|
||||
/*! On-hook = 0, Off-hook = 1 */
|
||||
unsigned int hookstate:1;
|
||||
/*! Unmuted = 0, Muted = 1 */
|
||||
|
@ -277,18 +279,19 @@ static void *stream_monitor(void *data)
|
|||
};
|
||||
|
||||
for (;;) {
|
||||
pthread_testcancel();
|
||||
console_pvt_lock(pvt);
|
||||
res = Pa_ReadStream(pvt->stream, buf, sizeof(buf) / sizeof(int16_t));
|
||||
console_pvt_unlock(pvt);
|
||||
pthread_testcancel();
|
||||
|
||||
if (!pvt->owner) {
|
||||
if (!pvt->owner || pvt->abort) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (res == paNoError)
|
||||
if (res == paNoError) {
|
||||
ast_queue_frame(pvt->owner, &f);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Console ReadStream failed: %s\n", Pa_GetErrorText(res));
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -403,8 +406,9 @@ static int stop_stream(struct console_pvt *pvt)
|
|||
if (!pvt->streamstate || pvt->thread == AST_PTHREADT_NULL)
|
||||
return 0;
|
||||
|
||||
pthread_cancel(pvt->thread);
|
||||
pthread_kill(pvt->thread, SIGURG);
|
||||
pvt->abort = 1;
|
||||
/* Wait for pvt->thread to exit cleanly, to avoid killing it while it's holding a lock. */
|
||||
pthread_kill(pvt->thread, SIGURG); /* Wake it up if needed, but don't cancel it */
|
||||
pthread_join(pvt->thread, NULL);
|
||||
|
||||
console_pvt_lock(pvt);
|
||||
|
|
|
@ -261,6 +261,21 @@
|
|||
completely disabled)</para>
|
||||
<para> <literal>voice</literal> Voice mode (returns from FAX mode, reverting the changes that were made)</para>
|
||||
</enum>
|
||||
<enum name="dialmode">
|
||||
<para>R/W Pulse and tone dialing mode of the channel.</para>
|
||||
<para>Disabling tone dialing using this option will not disable the DSP used for DTMF detection.
|
||||
To do that, also set the <literal>digitdetect</literal> option. If digit detection is disabled,
|
||||
DTMF will not be detected, regardless of the <literal>dialmode</literal> setting.
|
||||
The <literal>digitdetect</literal> setting has no impact on pulse dialing detection.</para>
|
||||
<para>If set, overrides the setting in <literal>chan_dahdi.conf</literal> for that channel.</para>
|
||||
<enumlist>
|
||||
<enum name="both" />
|
||||
<enum name="pulse" />
|
||||
<enum name="dtmf" />
|
||||
<enum name="tone" />
|
||||
<enum name="none" />
|
||||
</enumlist>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
<info name="Dial_Resource" language="en_US" tech="DAHDI">
|
||||
|
@ -1027,6 +1042,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
|
|||
#endif
|
||||
.chan = {
|
||||
.context = "default",
|
||||
.immediatering = 1,
|
||||
.cid_num = "",
|
||||
.cid_name = "",
|
||||
.cid_tag = "",
|
||||
|
@ -1034,6 +1050,7 @@ static struct dahdi_chan_conf dahdi_chan_conf_default(void)
|
|||
.mohsuggest = "",
|
||||
.parkinglot = "",
|
||||
.transfertobusy = 1,
|
||||
.dialmode = 0,
|
||||
|
||||
.ani_info_digits = 2,
|
||||
.ani_wink_time = 1000,
|
||||
|
@ -1447,6 +1464,18 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
|
|||
if (num)
|
||||
ast_copy_string(numbuf, num, ANALOG_MAX_CID);
|
||||
|
||||
if (flags & (CID_PRIVATE_NUMBER | CID_UNKNOWN_NUMBER)) {
|
||||
/* If we got a presentation, we must set it on the channel */
|
||||
struct ast_channel *chan = analog_p->ss_astchan;
|
||||
struct ast_party_caller caller;
|
||||
|
||||
ast_party_caller_set_init(&caller, ast_channel_caller(chan));
|
||||
caller.id.name.presentation = caller.id.number.presentation = (flags & CID_PRIVATE_NUMBER) ?
|
||||
AST_PRES_RESTRICTED | AST_PRES_USER_NUMBER_UNSCREENED : AST_PRES_UNAVAILABLE | AST_PRES_USER_NUMBER_UNSCREENED;
|
||||
ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
|
||||
ast_party_caller_free(&caller);
|
||||
}
|
||||
|
||||
ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1633,6 +1662,7 @@ static int my_callwait(void *pvt)
|
|||
static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *caller)
|
||||
{
|
||||
struct dahdi_pvt *p = pvt;
|
||||
struct analog_pvt *analog_p = p->sig_pvt;
|
||||
|
||||
ast_debug(2, "Starting cid spill\n");
|
||||
|
||||
|
@ -1644,13 +1674,20 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
|
|||
if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
|
||||
int pres = ast_party_id_presentation(&caller->id);
|
||||
if (cwcid == 0) {
|
||||
/* Some CPE support additional parameters for on-hook Caller*ID,
|
||||
* such as redirecting reason and call qualifier, so send those
|
||||
* if available.
|
||||
* I don't know of any CPE that supports this for Call Waiting (unfortunately),
|
||||
* so don't send those for call waiting as that will just lengthen the CID spill
|
||||
* for no good reason.
|
||||
*/
|
||||
p->cidlen = ast_callerid_full_generate(p->cidspill,
|
||||
caller->id.name.str,
|
||||
caller->id.number.str,
|
||||
NULL,
|
||||
-1,
|
||||
analog_p->redirecting_reason,
|
||||
pres,
|
||||
0,
|
||||
analog_p->call_qualifier,
|
||||
CID_TYPE_MDMF,
|
||||
AST_LAW(p));
|
||||
} else {
|
||||
|
@ -1991,6 +2028,9 @@ static void my_set_cadence(void *pvt, int *cid_rings, struct ast_channel *ast)
|
|||
ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast_channel_name(ast), strerror(errno));
|
||||
*cid_rings = cidrings[p->distinctivering - 1];
|
||||
} else {
|
||||
if (p->distinctivering > 0) {
|
||||
ast_log(LOG_WARNING, "Cadence %d is not defined, falling back to default ring cadence\n", p->distinctivering);
|
||||
}
|
||||
if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
|
||||
ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast_channel_name(ast), strerror(errno));
|
||||
*cid_rings = p->sendcalleridafter;
|
||||
|
@ -3447,7 +3487,7 @@ struct sig_ss7_callback sig_ss7_callbacks =
|
|||
*/
|
||||
static void notify_message(char *mailbox, int thereornot)
|
||||
{
|
||||
char s[sizeof(mwimonitornotify) + 80];
|
||||
char s[sizeof(mwimonitornotify) + 164];
|
||||
|
||||
if (ast_strlen_zero(mailbox)) {
|
||||
return;
|
||||
|
@ -4115,7 +4155,7 @@ static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_leve
|
|||
{
|
||||
#define CONTEXT_TAG "Context - "
|
||||
char logmsg[256];
|
||||
char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1];
|
||||
char completemsg[sizeof(logmsg) * 2];
|
||||
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
|
||||
snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg);
|
||||
dahdi_r2_write_log(level, completemsg);
|
||||
|
@ -4128,10 +4168,11 @@ static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level
|
|||
{
|
||||
#define CHAN_TAG "Chan "
|
||||
char logmsg[256];
|
||||
char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
|
||||
char completemsg[sizeof(logmsg) * 2];
|
||||
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
|
||||
snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d - %s", openr2_chan_get_number(r2chan), logmsg);
|
||||
dahdi_r2_write_log(level, completemsg);
|
||||
#undef CHAN_TAG
|
||||
}
|
||||
|
||||
static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
|
||||
|
@ -5189,6 +5230,18 @@ static int has_voicemail(struct dahdi_pvt *p)
|
|||
int new_msgs;
|
||||
RAII_VAR(struct stasis_message *, mwi_message, NULL, ao2_cleanup);
|
||||
|
||||
/* A manual MWI disposition has been requested, use that instead
|
||||
* if this is for sending the new MWI indication. */
|
||||
if (p->mwioverride_active) {
|
||||
/* We don't clear p->mwioverride_active automatically,
|
||||
* because otherwise do_monitor would just change it back to the way it was.
|
||||
* We need to keep the override active until explicitly disabled by the user,
|
||||
* so that we can keep returning the correct answer in subsequent calls to do_monitor. */
|
||||
ast_debug(6, "MWI manual override active on channel %d: pretending that it should be %s\n",
|
||||
p->channel, p->mwioverride_disposition ? "active" : "inactive");
|
||||
return p->mwioverride_disposition;
|
||||
}
|
||||
|
||||
mwi_message = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
|
||||
if (mwi_message) {
|
||||
struct ast_mwi_state *mwi_state = stasis_message_data(mwi_message);
|
||||
|
@ -6531,6 +6584,36 @@ hangup_out:
|
|||
ast_free(p->cidspill);
|
||||
p->cidspill = NULL;
|
||||
|
||||
if (p->reoriginate && p->sig == SIG_FXOKS && dahdi_analog_lib_handles(p->sig, p->radio, 0)) {
|
||||
/* Automatic reorigination: if all calls towards a user have hung up,
|
||||
* give dial tone again, so user doesn't need to cycle the hook state manually. */
|
||||
if (my_is_off_hook(p) && !p->owner) {
|
||||
/* 2 important criteria: channel must be off-hook, with no calls remaining (no owner) */
|
||||
ast_debug(1, "Queuing reorigination for channel %d\n", p->channel);
|
||||
my_play_tone(p, SUB_REAL, -1); /* Stop any congestion tone that may be present. */
|
||||
/* Must wait for the loop disconnect to end.
|
||||
* Sadly, these definitions are in dahdi/kernel.h, not dahdi/user.h
|
||||
* Calling usleep on an active DAHDI channel is a no-no, but this is okay.
|
||||
*/
|
||||
usleep(800000); /* DAHDI_KEWLTIME + DAHDI_AFTERKEWLTIME */
|
||||
/* If the line is still off-hook and ownerless, actually queue the reorigination.
|
||||
* do_monitor will actually go ahead and do it. */
|
||||
if (!p->owner && my_is_off_hook(p)) {
|
||||
p->doreoriginate = 1; /* Tell do_monitor to reoriginate this channel */
|
||||
/* Note, my_off_hook will fail if called before the loop disconnect has finished
|
||||
* (important for FXOKS signaled channels). This is because DAHDI will reject
|
||||
* DAHDI_OFFHOOK while the channel is in TXSTATE_KEWL or TXSTATE_AFTERKEWL,
|
||||
* so we have to wait for that to finish (see comment above).
|
||||
* do_monitor itself cannot block, so make the blocking usleep call
|
||||
* here in the channel thread instead.
|
||||
*/
|
||||
my_off_hook(p); /* Now, go ahead and take the channel back off hook (sig_analog put it on hook) */
|
||||
} else {
|
||||
ast_debug(1, "Channel %d is no longer eligible for reorigination (went back on hook or became in use)\n", p->channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_verb(3, "Hungup '%s'\n", ast_channel_name(ast));
|
||||
|
||||
|
@ -6655,6 +6738,14 @@ static int dahdi_queryoption(struct ast_channel *chan, int option, void *data, i
|
|||
}
|
||||
|
||||
switch (option) {
|
||||
case AST_OPTION_TDD:
|
||||
cp = (char *) data;
|
||||
if (p->mate) {
|
||||
*cp = 2;
|
||||
} else {
|
||||
*cp = p->tdd ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case AST_OPTION_DIGIT_DETECT:
|
||||
cp = (char *) data;
|
||||
*cp = p->ignoredtmf ? 0 : 1;
|
||||
|
@ -7008,6 +7099,32 @@ static int dahdi_func_read(struct ast_channel *chan, const char *function, char
|
|||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
} else if (!strcasecmp(data, "dialmode")) {
|
||||
struct analog_pvt *analog_p;
|
||||
ast_mutex_lock(&p->lock);
|
||||
analog_p = p->sig_pvt;
|
||||
/* Hardcode p->radio and p->oprmode as 0 since we're using this to check for analogness, not the handler */
|
||||
if (dahdi_analog_lib_handles(p->sig, 0, 0) && analog_p) {
|
||||
switch (analog_p->dialmode) {
|
||||
case ANALOG_DIALMODE_BOTH:
|
||||
ast_copy_string(buf, "both", len);
|
||||
break;
|
||||
case ANALOG_DIALMODE_PULSE:
|
||||
ast_copy_string(buf, "pulse", len);
|
||||
break;
|
||||
case ANALOG_DIALMODE_DTMF:
|
||||
ast_copy_string(buf, "dtmf", len);
|
||||
break;
|
||||
case ANALOG_DIALMODE_NONE:
|
||||
ast_copy_string(buf, "none", len);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
|
||||
*buf = '\0';
|
||||
res = -1;
|
||||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
} else {
|
||||
*buf = '\0';
|
||||
res = -1;
|
||||
|
@ -7113,6 +7230,30 @@ static int dahdi_func_write(struct ast_channel *chan, const char *function, char
|
|||
ast_log(LOG_WARNING, "Unsupported value '%s' provided for '%s' item.\n", value, data);
|
||||
res = -1;
|
||||
}
|
||||
} else if (!strcasecmp(data, "dialmode")) {
|
||||
struct analog_pvt *analog_p;
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
analog_p = p->sig_pvt;
|
||||
if (!dahdi_analog_lib_handles(p->sig, 0, 0) || !analog_p) {
|
||||
ast_log(LOG_WARNING, "%s only supported on analog channels\n", data);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
return -1;
|
||||
}
|
||||
/* analog pvt is used for pulse dialing, so update both */
|
||||
if (!strcasecmp(value, "pulse")) {
|
||||
p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_PULSE;
|
||||
} else if (!strcasecmp(value, "dtmf") || !strcasecmp(value, "tone")) {
|
||||
p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_DTMF;
|
||||
} else if (!strcasecmp(value, "none")) {
|
||||
p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_NONE;
|
||||
} else if (!strcasecmp(value, "both")) {
|
||||
p->dialmode = analog_p->dialmode = ANALOG_DIALMODE_BOTH;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "'%s' is an invalid setting for %s\n", value, data);
|
||||
res = -1;
|
||||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
@ -8996,6 +9137,13 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
|
|||
} else {
|
||||
dahdi_handle_dtmf(ast, idx, &f);
|
||||
}
|
||||
if (!(p->dialmode == ANALOG_DIALMODE_BOTH || p->dialmode == ANALOG_DIALMODE_DTMF)) {
|
||||
if (f->frametype == AST_FRAME_DTMF_END) { /* only show this message when the key is let go of */
|
||||
ast_debug(1, "Dropping DTMF digit '%c' because tone dialing is disabled\n", f->subclass.integer);
|
||||
}
|
||||
f->frametype = AST_FRAME_NULL;
|
||||
f->subclass.integer = 0;
|
||||
}
|
||||
break;
|
||||
case AST_FRAME_VOICE:
|
||||
if (p->cidspill || p->cid_suppress_expire) {
|
||||
|
@ -11753,7 +11901,7 @@ static void *do_monitor(void *data)
|
|||
&& (last->sig & __DAHDI_SIG_FXO)
|
||||
&& !analog_p->fxsoffhookstate
|
||||
&& !last->owner
|
||||
&& !ast_strlen_zero(last->mailbox)
|
||||
&& (!ast_strlen_zero(last->mailbox) || last->mwioverride_active)
|
||||
&& !analog_p->subs[SUB_REAL].owner /* could be a recall ring from a flash hook hold */
|
||||
&& (thispass - analog_p->onhooktime > 3)) {
|
||||
res = has_voicemail(last);
|
||||
|
@ -11901,6 +12049,26 @@ static void *do_monitor(void *data)
|
|||
else
|
||||
doomed = handle_init_event(i, res);
|
||||
}
|
||||
if (i->doreoriginate && res == DAHDI_EVENT_HOOKCOMPLETE) {
|
||||
/* Actually automatically reoriginate this FXS line, if directed to.
|
||||
* We should get a DAHDI_EVENT_HOOKCOMPLETE from the loop disconnect
|
||||
* doing its thing (one reason why this is for FXOKS only: FXOLS
|
||||
* hangups don't give us any DAHDI events to piggyback off of)*/
|
||||
i->doreoriginate = 0;
|
||||
/* Double check the channel is still off-hook. There's only about a millisecond
|
||||
* between when doreoriginate is set high and we see that here, but just to be safe. */
|
||||
if (!my_is_off_hook(i)) {
|
||||
ast_debug(1, "Woah! Went back on hook before reoriginate could happen on channel %d\n", i->channel);
|
||||
} else {
|
||||
ast_verb(3, "Automatic reorigination on channel %d\n", i->channel);
|
||||
res = DAHDI_EVENT_RINGOFFHOOK; /* Pretend that the physical channel just went off hook */
|
||||
if (dahdi_analog_lib_handles(i->sig, i->radio, i->oprmode)) {
|
||||
doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
|
||||
} else {
|
||||
doomed = handle_init_event(i, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
ast_mutex_lock(&iflock);
|
||||
}
|
||||
}
|
||||
|
@ -12778,7 +12946,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
}
|
||||
#endif
|
||||
tmp->immediate = conf->chan.immediate;
|
||||
tmp->immediatering = conf->chan.immediatering;
|
||||
tmp->transfertobusy = conf->chan.transfertobusy;
|
||||
tmp->dialmode = conf->chan.dialmode;
|
||||
if (chan_sig & __DAHDI_SIG_FXS) {
|
||||
tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
|
||||
tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
|
||||
|
@ -12805,6 +12975,8 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
tmp->usedistinctiveringdetection = usedistinctiveringdetection;
|
||||
tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
|
||||
tmp->threewaycalling = conf->chan.threewaycalling;
|
||||
tmp->threewaysilenthold = conf->chan.threewaysilenthold;
|
||||
tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
|
||||
tmp->adsi = conf->chan.adsi;
|
||||
tmp->use_smdi = conf->chan.use_smdi;
|
||||
tmp->permhidecallerid = conf->chan.hidecallerid;
|
||||
|
@ -12993,6 +13165,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
tmp->ani_wink_time = conf->chan.ani_wink_time;
|
||||
tmp->ani_timeout = conf->chan.ani_timeout;
|
||||
tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
|
||||
tmp->reoriginate = conf->chan.reoriginate;
|
||||
tmp->sendcalleridafter = conf->chan.sendcalleridafter;
|
||||
ast_cc_copy_config_params(tmp->cc_params, conf->chan.cc_params);
|
||||
|
||||
|
@ -13102,16 +13275,20 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
analog_p->ani_wink_time = conf->chan.ani_wink_time;
|
||||
analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
|
||||
analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
|
||||
analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
|
||||
analog_p->callreturn = conf->chan.callreturn;
|
||||
analog_p->cancallforward = conf->chan.cancallforward;
|
||||
analog_p->canpark = conf->chan.canpark;
|
||||
analog_p->dahditrcallerid = conf->chan.dahditrcallerid;
|
||||
analog_p->immediate = conf->chan.immediate;
|
||||
analog_p->permhidecallerid = conf->chan.permhidecallerid;
|
||||
analog_p->immediatering = conf->chan.immediatering;
|
||||
analog_p->permhidecallerid = conf->chan.hidecallerid; /* hidecallerid is the config setting, not permhidecallerid (~permcallwaiting above) */
|
||||
/* It's not necessary to set analog_p->hidecallerid here, sig_analog will set hidecallerid=permhidecaller before each call */
|
||||
analog_p->pulse = conf->chan.pulse;
|
||||
analog_p->threewaycalling = conf->chan.threewaycalling;
|
||||
analog_p->transfer = conf->chan.transfer;
|
||||
analog_p->transfertobusy = conf->chan.transfertobusy;
|
||||
analog_p->dialmode = conf->chan.dialmode;
|
||||
analog_p->use_callerid = tmp->use_callerid;
|
||||
analog_p->usedistinctiveringdetection = tmp->usedistinctiveringdetection;
|
||||
analog_p->use_smdi = tmp->use_smdi;
|
||||
|
@ -13651,6 +13828,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
|
|||
struct ast_channel *tmp = NULL;
|
||||
struct dahdi_pvt *exitpvt;
|
||||
int channelmatched = 0;
|
||||
int foundowner = 0;
|
||||
int groupmatched = 0;
|
||||
#if defined(HAVE_PRI) || defined(HAVE_SS7)
|
||||
int transcapdigital = 0;
|
||||
|
@ -13674,6 +13852,10 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
|
|||
if (start.roundrobin)
|
||||
round_robin[start.rr_starting_point] = p;
|
||||
|
||||
if (p->owner) {
|
||||
foundowner++;
|
||||
}
|
||||
|
||||
if (is_group_or_channel_match(p, start.span, start.groupmatch, &groupmatched, start.channelmatch, &channelmatched)
|
||||
&& available(&p, channelmatched)) {
|
||||
ast_debug(1, "Using channel %d\n", p->channel);
|
||||
|
@ -13792,7 +13974,7 @@ next:
|
|||
ast_mutex_unlock(&iflock);
|
||||
restart_monitor();
|
||||
if (cause && !tmp) {
|
||||
if (callwait || channelmatched) {
|
||||
if (callwait || (channelmatched && foundowner)) {
|
||||
*cause = AST_CAUSE_BUSY;
|
||||
} else if (groupmatched) {
|
||||
*cause = AST_CAUSE_CONGESTION;
|
||||
|
@ -16371,6 +16553,75 @@ static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static char *dahdi_set_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
int channel;
|
||||
int on;
|
||||
int override = 1;
|
||||
struct dahdi_pvt *dahdi_chan = NULL;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "dahdi set mwi";
|
||||
e->usage =
|
||||
"Usage: dahdi set mwi <chan#> <on|off|reset>\n"
|
||||
" Sets/unsets MWI (Message Waiting Indicator) manually on a channel.\n"
|
||||
" This may be used regardless of whether the channel is assigned any mailboxes.\n"
|
||||
" When active, this setting will override the voicemail status to set MWI.\n"
|
||||
" Once cleared, the voicemail status will resume control of MWI.\n"
|
||||
" Changes are queued for when the channel is idle and persist until cleared.\n"
|
||||
" <chan num> is the channel number\n"
|
||||
" <on|off|reset> Enable, disable, or reset Message Waiting Indicator override?\n"
|
||||
;
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != 5)
|
||||
return CLI_SHOWUSAGE;
|
||||
|
||||
if ((channel = atoi(a->argv[3])) <= 0) {
|
||||
ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
if (ast_true(a->argv[4])) {
|
||||
on = 1;
|
||||
} else if (ast_false(a->argv[4])) {
|
||||
on = 0;
|
||||
} else if (!strcmp(a->argv[4], "reset")) {
|
||||
override = 0;
|
||||
} else {
|
||||
ast_cli(a->fd, "Expected 'on' or 'off' or 'reset', got '%s'\n", a->argv[4]);
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
ast_mutex_lock(&iflock);
|
||||
for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
|
||||
if (dahdi_chan->channel != channel)
|
||||
continue;
|
||||
|
||||
/* Found the channel. Actually set it */
|
||||
if (override) {
|
||||
dahdi_chan->mwioverride_disposition = on;
|
||||
ast_cli(a->fd, "MWI '%s' queued for channel %d\n", on ? "enable" : "disable", channel);
|
||||
}
|
||||
dahdi_chan->mwioverride_active = override;
|
||||
/* The do_monitor thread will take care of actually sending the MWI
|
||||
* at an appropriate time for the channel. */
|
||||
break;
|
||||
}
|
||||
ast_mutex_unlock(&iflock);
|
||||
|
||||
if (!dahdi_chan) {
|
||||
ast_cli(a->fd, "Unable to find given channel %d\n", channel);
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry dahdi_cli[] = {
|
||||
AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
|
||||
AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
|
||||
|
@ -16383,6 +16634,7 @@ static struct ast_cli_entry dahdi_cli[] = {
|
|||
AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
|
||||
AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
|
||||
AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
|
||||
AST_CLI_DEFINE(dahdi_set_mwi, "Sets/unsets MWI (Message Waiting Indicator) manually on a channel"),
|
||||
};
|
||||
|
||||
#define TRANSFER 0
|
||||
|
@ -18144,6 +18396,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
confp->chan.cid_start = CID_START_RING;
|
||||
} else if (!strcasecmp(v->name, "threewaycalling")) {
|
||||
confp->chan.threewaycalling = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "threewaysilenthold")) {
|
||||
confp->chan.threewaysilenthold = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "cancallforward")) {
|
||||
confp->chan.cancallforward = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "relaxdtmf")) {
|
||||
|
@ -18186,6 +18440,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
confp->chan.busycount = atoi(v->value);
|
||||
} else if (!strcasecmp(v->name, "busypattern")) {
|
||||
parse_busy_pattern(v, &confp->chan.busy_cadence);
|
||||
} else if (!strcasecmp(v->name, "calledsubscriberheld")) {
|
||||
confp->chan.calledsubscriberheld = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "callprogress")) {
|
||||
confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
|
||||
if (ast_true(v->value))
|
||||
|
@ -18275,18 +18531,30 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
} else if (!strcasecmp(v->name, "group")) {
|
||||
confp->chan.group = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "callgroup")) {
|
||||
if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
|
||||
ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a call group\n");
|
||||
}
|
||||
if (!strcasecmp(v->value, "none"))
|
||||
confp->chan.callgroup = 0;
|
||||
else
|
||||
confp->chan.callgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "pickupgroup")) {
|
||||
if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
|
||||
ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a pickup group\n");
|
||||
}
|
||||
if (!strcasecmp(v->value, "none"))
|
||||
confp->chan.pickupgroup = 0;
|
||||
else
|
||||
confp->chan.pickupgroup = ast_get_group(v->value);
|
||||
} else if (!strcasecmp(v->name, "namedcallgroup")) {
|
||||
if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
|
||||
ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named call group\n");
|
||||
}
|
||||
confp->chan.named_callgroups = ast_get_namedgroups(v->value);
|
||||
} else if (!strcasecmp(v->name, "namedpickupgroup")) {
|
||||
if (!((confp->chan.sig == SIG_FXOKS) || (confp->chan.sig == SIG_FXOGS) || (confp->chan.sig == SIG_FXOLS))) {
|
||||
ast_log(LOG_WARNING, "Only FXO signalled channels may belong to a named pickup group\n");
|
||||
}
|
||||
confp->chan.named_pickupgroups = ast_get_namedgroups(v->value);
|
||||
} else if (!strcasecmp(v->name, "setvar")) {
|
||||
if (v->value) {
|
||||
|
@ -18306,8 +18574,20 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
}
|
||||
} else if (!strcasecmp(v->name, "immediate")) {
|
||||
confp->chan.immediate = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "immediatering")) {
|
||||
confp->chan.immediatering = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "transfertobusy")) {
|
||||
confp->chan.transfertobusy = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "dialmode")) {
|
||||
if (!strcasecmp(v->value, "pulse")) {
|
||||
confp->chan.dialmode = ANALOG_DIALMODE_PULSE;
|
||||
} else if (!strcasecmp(v->value, "dtmf") || !strcasecmp(v->value, "tone")) {
|
||||
confp->chan.dialmode = ANALOG_DIALMODE_DTMF;
|
||||
} else if (!strcasecmp(v->value, "none")) {
|
||||
confp->chan.dialmode = ANALOG_DIALMODE_NONE;
|
||||
} else {
|
||||
confp->chan.dialmode = ANALOG_DIALMODE_BOTH;
|
||||
}
|
||||
} else if (!strcasecmp(v->name, "mwimonitor")) {
|
||||
confp->chan.mwimonitor_neon = 0;
|
||||
confp->chan.mwimonitor_fsk = 0;
|
||||
|
@ -18406,6 +18686,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
confp->chan.ani_timeout = atoi(v->value);
|
||||
} else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
|
||||
confp->chan.hanguponpolarityswitch = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "autoreoriginate")) {
|
||||
confp->chan.reoriginate = ast_true(v->value);
|
||||
} else if (!strcasecmp(v->name, "sendcalleridafter")) {
|
||||
confp->chan.sendcalleridafter = atoi(v->value);
|
||||
} else if (!strcasecmp(v->name, "mwimonitornotify")) {
|
||||
|
@ -19411,7 +19693,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
report_alarms = REPORT_SPAN_ALARMS;
|
||||
}
|
||||
} else if (!(options & PROC_DAHDI_OPT_NOWARN) )
|
||||
ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
|
||||
ast_log(LOG_NOTICE, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
|
||||
}
|
||||
|
||||
if (dahdichan) {
|
||||
|
|
|
@ -146,6 +146,7 @@ struct dahdi_pvt {
|
|||
* \note Set to a couple of nonzero values but it is only tested like a boolean.
|
||||
*/
|
||||
int radio;
|
||||
int dialmode; /*!< Dialing Modes Allowed (Pulse/Tone) */
|
||||
int outsigmod; /*!< Outbound Signalling style (modifier) */
|
||||
int oprmode; /*!< "Operator Services" mode */
|
||||
struct dahdi_pvt *oprpeer; /*!< "Operator Services" peer tech_pvt ptr */
|
||||
|
@ -203,6 +204,13 @@ struct dahdi_pvt {
|
|||
* \note Set from the "busydetect" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int busydetect:1;
|
||||
/*!
|
||||
* \brief TRUE if Called Subscriber held is enabled.
|
||||
* This allows a single incoming call to hold a DAHDI channel up,
|
||||
* allowing a recipient to hang up an extension and pick up another
|
||||
* phone on the same line without disconnecting the call.
|
||||
*/
|
||||
unsigned int calledsubscriberheld:1;
|
||||
/*!
|
||||
* \brief TRUE if call return is enabled.
|
||||
* (*69, if your dialplan doesn't catch this first)
|
||||
|
@ -275,6 +283,14 @@ struct dahdi_pvt {
|
|||
* \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int hanguponpolarityswitch:1;
|
||||
/*!
|
||||
* \brief TRUE if FXS (FXO-signalled) channel should reoriginate for user to make a new call.
|
||||
*/
|
||||
unsigned int reoriginate:1;
|
||||
/*!
|
||||
* \brief Internal flag for if we should actually process a reorigination.
|
||||
*/
|
||||
unsigned int doreoriginate:1;
|
||||
/*! \brief TRUE if DTMF detection needs to be done by hardware. */
|
||||
unsigned int hardwaredtmf:1;
|
||||
/*!
|
||||
|
@ -298,6 +314,12 @@ struct dahdi_pvt {
|
|||
* \note Set from the "immediate" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int immediate:1;
|
||||
/*!
|
||||
* \brief TRUE if audible ringback should be provided
|
||||
* when immediate = yes.
|
||||
* \note Set from the "immediatering" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int immediatering:1;
|
||||
/*! \brief TRUE if in an alarm condition. */
|
||||
unsigned int inalarm:1;
|
||||
/*! \brief TRUE if TDD in MATE mode */
|
||||
|
@ -344,6 +366,11 @@ struct dahdi_pvt {
|
|||
* \note Set from the "threewaycalling" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int threewaycalling:1;
|
||||
/*!
|
||||
* \brief TRUE if a three way dial tone should time out to silence
|
||||
* \note Set from the "threewaysilenthold" value read in from chan_dahdi.conf
|
||||
*/
|
||||
unsigned int threewaysilenthold:1;
|
||||
/*!
|
||||
* \brief TRUE if call transfer is enabled
|
||||
* \note For FXS ports (either direct analog or over T1/E1):
|
||||
|
@ -404,6 +431,10 @@ struct dahdi_pvt {
|
|||
unsigned int mwimonitoractive:1;
|
||||
/*! \brief TRUE if a MWI message sending thread is active */
|
||||
unsigned int mwisendactive:1;
|
||||
/*! \brief TRUE if a manual MWI override is active for a channel */
|
||||
unsigned int mwioverride_active:1;
|
||||
/*! \brief Manual MWI disposition (on/off) */
|
||||
unsigned int mwioverride_disposition:1;
|
||||
/*!
|
||||
* \brief TRUE if channel is out of reset and ready
|
||||
* \note Used by SS7. Otherwise set but not used.
|
||||
|
|
|
@ -226,6 +226,16 @@
|
|||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
<info name="Dial_Resource" language="en_US" tech="IAX2">
|
||||
<para>The general syntax is:</para>
|
||||
<para><literal>Dial(IAX2/[username[:password]@]peer[:port][/exten[@context]][/options]</literal></para>
|
||||
<para>IAX2 optionally allows modifiers to be specified after the extension.</para>
|
||||
<enumlist>
|
||||
<enum name="a">
|
||||
<para>Request auto answer (supporting equipment/configuration required)</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
<manager name="IAXpeers" language="en_US">
|
||||
<synopsis>
|
||||
List IAX peers.
|
||||
|
@ -388,6 +398,47 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
|
|||
#define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */
|
||||
#define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */
|
||||
|
||||
/*! \brief Name of effective auth method */
|
||||
static const char *auth_method_labels[] = {
|
||||
[0] = "none",
|
||||
[IAX_AUTH_PLAINTEXT] = "plaintext",
|
||||
[IAX_AUTH_MD5] = "MD5",
|
||||
[IAX_AUTH_RSA] = "RSA",
|
||||
};
|
||||
|
||||
/* Max length is length of |RSA|MD5|plaintext (18 + 1 for NUL = 19) */
|
||||
#define AUTH_METHOD_NAMES_BUFSIZE 19
|
||||
|
||||
/*!
|
||||
* \brief Get names of all auth methods
|
||||
* \param Bit field of auth methods
|
||||
* \param[out] buf Buffer into which to write the names. Must be of size AUTH_METHOD_NAMES_BUFSIZE.
|
||||
* \return Auth methods name
|
||||
*/
|
||||
static char *auth_method_names(int authmethods, char *restrict buf)
|
||||
{
|
||||
char *pos = buf;
|
||||
|
||||
*pos = '\0';
|
||||
|
||||
if (authmethods & IAX_AUTH_RSA) {
|
||||
pos += sprintf(pos, "|RSA");
|
||||
}
|
||||
if (authmethods & IAX_AUTH_MD5) {
|
||||
pos += sprintf(pos, "|MD5");
|
||||
}
|
||||
if (authmethods & IAX_AUTH_PLAINTEXT) {
|
||||
pos += sprintf(pos, "|plaintext");
|
||||
}
|
||||
|
||||
if (pos == buf) { /* No auth methods */
|
||||
strcpy(buf, "none");
|
||||
return buf;
|
||||
}
|
||||
|
||||
return buf + 1; /* Skip leading | */
|
||||
}
|
||||
|
||||
/* if a pvt has encryption setup done and is running on the call */
|
||||
#define IAX_CALLENCRYPTED(pvt) \
|
||||
(ast_test_flag64(pvt, IAX_ENCRYPTED) && ast_test_flag64(pvt, IAX_KEYPOPULATED))
|
||||
|
@ -815,6 +866,8 @@ struct chan_iax2_pvt {
|
|||
int authrej;
|
||||
/*! permitted authentication methods */
|
||||
int authmethods;
|
||||
/*! effective authentication method */
|
||||
int eff_auth_method;
|
||||
/*! permitted encryption methods */
|
||||
int encmethods;
|
||||
/*! Encryption AES-128 Key */
|
||||
|
@ -3407,7 +3460,7 @@ static int send_packet(struct iax_frame *f)
|
|||
|
||||
/* Called with iaxsl held */
|
||||
if (iaxdebug) {
|
||||
ast_debug(3, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
|
||||
ast_debug(8, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
|
||||
}
|
||||
if (f->transfer) {
|
||||
iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
|
||||
|
@ -4148,9 +4201,19 @@ static void __get_from_jb(const void *p)
|
|||
now.tv_usec += 1000;
|
||||
|
||||
ms = ast_tvdiff_ms(now, pvt->rxcore);
|
||||
|
||||
voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
|
||||
if (voicefmt && ms >= (next = jb_next(pvt->jb))) {
|
||||
if (ms >= (next = jb_next(pvt->jb))) {
|
||||
voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
|
||||
if (!voicefmt) {
|
||||
/* pvt->voiceformat won't be set if we haven't received any voice frames yet.
|
||||
* In this case, fall back to using the format negotiated during call setup,
|
||||
* so we don't stall the jitterbuffer completely. */
|
||||
voicefmt = ast_format_compatibility_bitfield2format(pvt->peerformat);
|
||||
}
|
||||
if (!voicefmt) {
|
||||
/* Really shouldn't happen, but if it does, should be looked into */
|
||||
ast_log(LOG_WARNING, "No voice format and no peer format available on %s, backlogging frame\n", ast_channel_name(pvt->owner));
|
||||
goto cleanup; /* Don't crash if there's no voice format */
|
||||
}
|
||||
ret = jb_get(pvt->jb, &frame, ms, ast_format_get_default_ms(voicefmt));
|
||||
switch(ret) {
|
||||
case JB_OK:
|
||||
|
@ -4192,6 +4255,7 @@ static void __get_from_jb(const void *p)
|
|||
break;
|
||||
}
|
||||
}
|
||||
cleanup:
|
||||
if (pvt)
|
||||
update_jbsched(pvt);
|
||||
ast_mutex_unlock(&iaxsl[callno]);
|
||||
|
@ -6384,7 +6448,7 @@ static int invalid_key(ast_aes_decrypt_key *ecx)
|
|||
#ifdef HAVE_OPENSSL
|
||||
int i;
|
||||
for (i = 0; i < 60; i++) {
|
||||
if (ecx->rd_key[i]) {
|
||||
if (ecx->raw[i]) {
|
||||
return 0; /* stop if we encounter anything non-zero */
|
||||
}
|
||||
}
|
||||
|
@ -8168,7 +8232,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
|
|||
user = user_unref(user);
|
||||
}
|
||||
if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) {
|
||||
ast_log(LOG_NOTICE, "Call Terminated, Incoming call is unencrypted while force encrypt is enabled.\n");
|
||||
ast_log(LOG_WARNING, "Call Terminated, incoming call is unencrypted while force encrypt is enabled.\n");
|
||||
return res;
|
||||
}
|
||||
if (!ast_test_flag(&p->state, IAX_STATE_AUTHENTICATED))
|
||||
|
@ -8194,12 +8258,17 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
|
|||
key = ast_key_get(keyn, AST_KEY_PUBLIC);
|
||||
if (key && !ast_check_signature(key, p->challenge, rsasecret)) {
|
||||
res = 0;
|
||||
p->eff_auth_method = IAX_AUTH_RSA;
|
||||
break;
|
||||
} else if (!key)
|
||||
ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
|
||||
} else if (!key) {
|
||||
ast_log(LOG_WARNING, "Requested inkey '%s' for RSA authentication does not exist\n", keyn);
|
||||
}
|
||||
keyn = strsep(&stringp, ":");
|
||||
}
|
||||
ast_free(tmpkey);
|
||||
if (res && authdebug) {
|
||||
ast_log(LOG_WARNING, "No RSA public keys on file matched incoming call\n");
|
||||
}
|
||||
} else if (p->authmethods & IAX_AUTH_MD5) {
|
||||
struct MD5Context md5;
|
||||
unsigned char digest[16];
|
||||
|
@ -8216,12 +8285,19 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
|
|||
sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
|
||||
if (!strcasecmp(requeststr, md5secret)) {
|
||||
res = 0;
|
||||
p->eff_auth_method = IAX_AUTH_MD5;
|
||||
break;
|
||||
} else if (authdebug) {
|
||||
ast_log(LOG_WARNING, "MD5 secret mismatch\n");
|
||||
}
|
||||
}
|
||||
} else if (p->authmethods & IAX_AUTH_PLAINTEXT) {
|
||||
if (!strcmp(secret, p->secret))
|
||||
if (!strcmp(secret, p->secret)) {
|
||||
res = 0;
|
||||
p->eff_auth_method = IAX_AUTH_PLAINTEXT;
|
||||
} else if (authdebug) {
|
||||
ast_log(LOG_WARNING, "Plaintext secret mismatch\n");
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -8396,22 +8472,25 @@ static int authenticate(const char *challenge, const char *secret, const char *k
|
|||
if (!ast_strlen_zero(keyn)) {
|
||||
if (!(authmethods & IAX_AUTH_RSA)) {
|
||||
if (ast_strlen_zero(secret)) {
|
||||
ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_sockaddr_stringify_addr(addr));
|
||||
ast_log(LOG_WARNING, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_sockaddr_stringify_addr(addr));
|
||||
}
|
||||
} else if (ast_strlen_zero(challenge)) {
|
||||
ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_sockaddr_stringify_addr(addr));
|
||||
ast_log(LOG_WARNING, "No challenge provided for RSA authentication to %s\n", ast_sockaddr_stringify_addr(addr));
|
||||
} else {
|
||||
char sig[256];
|
||||
struct ast_key *key;
|
||||
key = ast_key_get(keyn, AST_KEY_PRIVATE);
|
||||
if (!key) {
|
||||
ast_log(LOG_NOTICE, "Unable to find private key '%s'\n", keyn);
|
||||
ast_log(LOG_WARNING, "Unable to find private key '%s'\n", keyn);
|
||||
} else {
|
||||
if (ast_sign(key, (char*)challenge, sig)) {
|
||||
ast_log(LOG_NOTICE, "Unable to sign challenge with key\n");
|
||||
ast_log(LOG_WARNING, "Unable to sign challenge with key\n");
|
||||
res = -1;
|
||||
} else {
|
||||
iax_ie_append_str(ied, IAX_IE_RSA_RESULT, sig);
|
||||
if (pvt) {
|
||||
pvt->eff_auth_method = IAX_AUTH_RSA;
|
||||
}
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
@ -8444,11 +8523,15 @@ static int authenticate(const char *challenge, const char *secret, const char *k
|
|||
sprintf(digres + (x << 1), "%02hhx", digest[x]); /* safe */
|
||||
if (pvt) {
|
||||
build_encryption_keys(digest, pvt);
|
||||
pvt->eff_auth_method = IAX_AUTH_MD5;
|
||||
}
|
||||
iax_ie_append_str(ied, IAX_IE_MD5_RESULT, digres);
|
||||
res = 0;
|
||||
} else if (authmethods & IAX_AUTH_PLAINTEXT) {
|
||||
iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
|
||||
if (pvt) {
|
||||
pvt->eff_auth_method = IAX_AUTH_PLAINTEXT;
|
||||
}
|
||||
res = 0;
|
||||
} else
|
||||
ast_log(LOG_WARNING, "No way to send secret to peer '%s' (their methods: %d)\n", ast_sockaddr_stringify_addr(addr), authmethods);
|
||||
|
@ -10363,7 +10446,7 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
}
|
||||
if (ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED) && !decrypted) {
|
||||
if (decrypt_frame(fr->callno, fh, &f, &res)) {
|
||||
ast_log(LOG_NOTICE, "Packet Decrypt Failed!\n");
|
||||
ast_log(LOG_WARNING, "Packet Decrypt Failed!\n");
|
||||
ast_variables_destroy(ies.vars);
|
||||
ast_mutex_unlock(&iaxsl[fr->callno]);
|
||||
return 1;
|
||||
|
@ -11290,7 +11373,7 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
}
|
||||
if (authenticate_verify(iaxs[fr->callno], &ies)) {
|
||||
if (authdebug)
|
||||
ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_sockaddr_stringify(&addr),
|
||||
ast_log(LOG_WARNING, "Host %s failed to authenticate as %s\n", ast_sockaddr_stringify(&addr),
|
||||
iaxs[fr->callno]->username);
|
||||
memset(&ied0, 0, sizeof(ied0));
|
||||
auth_fail(fr->callno, IAX_COMMAND_REJECT);
|
||||
|
@ -11303,7 +11386,7 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
exists = 0;
|
||||
if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
|
||||
if (authdebug)
|
||||
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
|
||||
ast_log(LOG_WARNING, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iaxs[fr->callno]->exten,
|
||||
iaxs[fr->callno]->context);
|
||||
|
@ -11358,12 +11441,12 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
if (!format) {
|
||||
if (authdebug) {
|
||||
if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
|
||||
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
|
||||
ast_log(LOG_WARNING, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
|
||||
ast_log(LOG_WARNING, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
|
||||
|
@ -11416,12 +11499,12 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
|
||||
if (authdebug) {
|
||||
if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
|
||||
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
|
||||
ast_log(LOG_WARNING, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
|
||||
ast_log(LOG_WARNING, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
|
||||
iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
|
||||
|
@ -11445,8 +11528,12 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
iax_ie_append_versioned_uint64(&ied1, IAX_IE_FORMAT2, 0, format);
|
||||
send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACCEPT, 0, ied1.buf, ied1.pos, -1);
|
||||
if (strcmp(iaxs[fr->callno]->exten, "TBD")) {
|
||||
char authmethodnames[AUTH_METHOD_NAMES_BUFSIZE];
|
||||
ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
|
||||
ast_verb(3, "Accepting AUTHENTICATED call from %s:\n"
|
||||
"%srequested auth methods = (%s),\n"
|
||||
"%sactual auth method = %s,\n"
|
||||
"%sencrypted = %s,\n"
|
||||
"%srequested format = %s,\n"
|
||||
"%srequested prefs = %s,\n"
|
||||
"%sactual format = %s,\n"
|
||||
|
@ -11454,6 +11541,12 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
"%spriority = %s\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
VERBOSE_PREFIX_4,
|
||||
auth_method_names(iaxs[fr->callno]->authmethods, authmethodnames),
|
||||
VERBOSE_PREFIX_4,
|
||||
auth_method_labels[iaxs[fr->callno]->eff_auth_method],
|
||||
VERBOSE_PREFIX_4,
|
||||
IAX_CALLENCRYPTED(iaxs[fr->callno]) ? "yes" : "no",
|
||||
VERBOSE_PREFIX_4,
|
||||
iax2_getformatname(iaxs[fr->callno]->peerformat),
|
||||
VERBOSE_PREFIX_4,
|
||||
caller_pref_buf,
|
||||
|
@ -11522,7 +11615,7 @@ immediatedial:
|
|||
ast_string_field_set(iaxs[fr->callno], exten, ies.called_number ? ies.called_number : "s");
|
||||
if (!ast_exists_extension(NULL, iaxs[fr->callno]->context, iaxs[fr->callno]->exten, 1, iaxs[fr->callno]->cid_num)) {
|
||||
if (authdebug)
|
||||
ast_log(LOG_NOTICE, "Rejected dial attempt from %s, request '%s@%s' does not exist\n",
|
||||
ast_log(LOG_WARNING, "Rejected dial attempt from %s, request '%s@%s' does not exist\n",
|
||||
ast_sockaddr_stringify(&addr),
|
||||
iaxs[fr->callno]->exten,
|
||||
iaxs[fr->callno]->context);
|
||||
|
@ -12033,7 +12126,7 @@ immediatedial:
|
|||
iaxs[fr->callno]->last = fr->ts;
|
||||
#if 1
|
||||
if (iaxdebug)
|
||||
ast_debug(3, "For call=%d, set last=%u\n", fr->callno, fr->ts);
|
||||
ast_debug(8, "For call=%d, set last=%u\n", fr->callno, fr->ts);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -14302,7 +14395,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
|
|||
ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten);
|
||||
}
|
||||
|
||||
if (ast_check_hangup(chan)) {
|
||||
if (chan && ast_check_hangup(chan)) {
|
||||
doabort = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,6 +167,14 @@ static struct ast_sip_session_supplement chan_pjsip_ack_supplement = {
|
|||
.incoming_request = chan_pjsip_incoming_ack,
|
||||
};
|
||||
|
||||
static int chan_pjsip_incoming_prack(struct ast_sip_session *session, struct pjsip_rx_data *rdata);
|
||||
|
||||
static struct ast_sip_session_supplement chan_pjsip_prack_supplement = {
|
||||
.method = "PRACK",
|
||||
.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
|
||||
.incoming_request = chan_pjsip_incoming_prack,
|
||||
};
|
||||
|
||||
/*! \brief Function called by RTP engine to get local audio RTP peer */
|
||||
static enum ast_rtp_glue_result chan_pjsip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
|
||||
{
|
||||
|
@ -1564,13 +1572,22 @@ static int send_topology_change_refresh(void *data)
|
|||
{
|
||||
struct topology_change_refresh_data *refresh_data = data;
|
||||
struct ast_sip_session *session = refresh_data->session;
|
||||
enum ast_channel_state state = ast_channel_state(session->channel);
|
||||
enum ast_sip_session_refresh_method method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
|
||||
int ret;
|
||||
SCOPE_ENTER(3, "%s: %s\n", ast_sip_session_get_name(session),
|
||||
ast_str_tmp(256, ast_stream_topology_to_str(refresh_data->media_state->topology, &STR_TMP)));
|
||||
|
||||
/* See RFC 6337, especially section 3.2: If the early media SDP was sent reliably, we are allowed
|
||||
* to send UPDATEs. Only relevant for AST_STATE_RINGING and AST_STATE_RING - if the channel is UP,
|
||||
* re-INVITES can be sent.
|
||||
*/
|
||||
if (session->early_confirmed && (state == AST_STATE_RINGING || state == AST_STATE_RING)) {
|
||||
method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
|
||||
}
|
||||
|
||||
ret = ast_sip_session_refresh(session, NULL, NULL, on_topology_change_response,
|
||||
AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1, refresh_data->media_state);
|
||||
method, 1, refresh_data->media_state);
|
||||
refresh_data->media_state = NULL;
|
||||
topology_change_refresh_data_free(refresh_data);
|
||||
|
||||
|
@ -2513,6 +2530,15 @@ static int hangup(void *data)
|
|||
if (session) {
|
||||
int cause = h_data->cause;
|
||||
|
||||
if (channel->session->active_media_state &&
|
||||
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
|
||||
struct ast_sip_session_media *media =
|
||||
channel->session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
|
||||
if (media->rtp) {
|
||||
ast_rtp_instance_set_stats_vars(ast, media->rtp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It's possible that session_terminate might cause the session to be destroyed
|
||||
* immediately so we need to keep a reference to it so we can NULL session->channel
|
||||
|
@ -2872,97 +2898,6 @@ static int chan_pjsip_sendtext(struct ast_channel *ast, const char *text)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*! \brief Convert SIP hangup causes to Asterisk hangup causes */
|
||||
static int hangup_sip2cause(int cause)
|
||||
{
|
||||
/* Possible values taken from causes.h */
|
||||
|
||||
switch(cause) {
|
||||
case 401: /* Unauthorized */
|
||||
return AST_CAUSE_CALL_REJECTED;
|
||||
case 403: /* Not found */
|
||||
return AST_CAUSE_CALL_REJECTED;
|
||||
case 404: /* Not found */
|
||||
return AST_CAUSE_UNALLOCATED;
|
||||
case 405: /* Method not allowed */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 407: /* Proxy authentication required */
|
||||
return AST_CAUSE_CALL_REJECTED;
|
||||
case 408: /* No reaction */
|
||||
return AST_CAUSE_NO_USER_RESPONSE;
|
||||
case 409: /* Conflict */
|
||||
return AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
|
||||
case 410: /* Gone */
|
||||
return AST_CAUSE_NUMBER_CHANGED;
|
||||
case 411: /* Length required */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 413: /* Request entity too large */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 414: /* Request URI too large */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 415: /* Unsupported media type */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 420: /* Bad extension */
|
||||
return AST_CAUSE_NO_ROUTE_DESTINATION;
|
||||
case 480: /* No answer */
|
||||
return AST_CAUSE_NO_ANSWER;
|
||||
case 481: /* No answer */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 482: /* Loop detected */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 483: /* Too many hops */
|
||||
return AST_CAUSE_NO_ANSWER;
|
||||
case 484: /* Address incomplete */
|
||||
return AST_CAUSE_INVALID_NUMBER_FORMAT;
|
||||
case 485: /* Ambiguous */
|
||||
return AST_CAUSE_UNALLOCATED;
|
||||
case 486: /* Busy everywhere */
|
||||
return AST_CAUSE_BUSY;
|
||||
case 487: /* Request terminated */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 488: /* No codecs approved */
|
||||
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
|
||||
case 491: /* Request pending */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 493: /* Undecipherable */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 500: /* Server internal failure */
|
||||
return AST_CAUSE_FAILURE;
|
||||
case 501: /* Call rejected */
|
||||
return AST_CAUSE_FACILITY_REJECTED;
|
||||
case 502:
|
||||
return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||
case 503: /* Service unavailable */
|
||||
return AST_CAUSE_CONGESTION;
|
||||
case 504: /* Gateway timeout */
|
||||
return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
|
||||
case 505: /* SIP version not supported */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
case 600: /* Busy everywhere */
|
||||
return AST_CAUSE_USER_BUSY;
|
||||
case 603: /* Decline */
|
||||
return AST_CAUSE_CALL_REJECTED;
|
||||
case 604: /* Does not exist anywhere */
|
||||
return AST_CAUSE_UNALLOCATED;
|
||||
case 606: /* Not acceptable */
|
||||
return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
|
||||
default:
|
||||
if (cause < 500 && cause >= 400) {
|
||||
/* 4xx class error that is unknown - someting wrong with our request */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
} else if (cause < 600 && cause >= 500) {
|
||||
/* 5xx class error - problem in the remote end */
|
||||
return AST_CAUSE_CONGESTION;
|
||||
} else if (cause < 700 && cause >= 600) {
|
||||
/* 6xx - global errors in the 4xx class */
|
||||
return AST_CAUSE_INTERWORKING;
|
||||
}
|
||||
return AST_CAUSE_NORMAL;
|
||||
}
|
||||
/* Never reached */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void chan_pjsip_session_begin(struct ast_sip_session *session)
|
||||
{
|
||||
RAII_VAR(struct ast_datastore *, datastore, NULL, ao2_cleanup);
|
||||
|
@ -2993,11 +2928,21 @@ static void chan_pjsip_session_end(struct ast_sip_session *session)
|
|||
SCOPE_EXIT_RTN("No channel\n");
|
||||
}
|
||||
|
||||
|
||||
if (session->active_media_state &&
|
||||
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO]) {
|
||||
struct ast_sip_session_media *media =
|
||||
session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
|
||||
if (media->rtp) {
|
||||
ast_rtp_instance_set_stats_vars(session->channel, media->rtp);
|
||||
}
|
||||
}
|
||||
|
||||
chan_pjsip_remove_hold(ast_channel_uniqueid(session->channel));
|
||||
|
||||
ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0);
|
||||
if (!ast_channel_hangupcause(session->channel) && session->inv_session) {
|
||||
int cause = hangup_sip2cause(session->inv_session->cause);
|
||||
int cause = ast_sip_hangup_sip2cause(session->inv_session->cause);
|
||||
|
||||
ast_queue_hangup_with_cause(session->channel, cause);
|
||||
} else {
|
||||
|
@ -3009,11 +2954,11 @@ static void chan_pjsip_session_end(struct ast_sip_session *session)
|
|||
|
||||
static void set_sipdomain_variable(struct ast_sip_session *session)
|
||||
{
|
||||
pjsip_sip_uri *sip_ruri = pjsip_uri_get_uri(session->request_uri);
|
||||
size_t size = pj_strlen(&sip_ruri->host) + 1;
|
||||
const pj_str_t *host = ast_sip_pjsip_uri_get_hostname(session->request_uri);
|
||||
size_t size = pj_strlen(host) + 1;
|
||||
char *domain = ast_alloca(size);
|
||||
|
||||
ast_copy_pj_str(domain, &sip_ruri->host, size);
|
||||
ast_copy_pj_str(domain, host, size);
|
||||
|
||||
pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain);
|
||||
return;
|
||||
|
@ -3191,7 +3136,7 @@ static void chan_pjsip_incoming_response_update_cause(struct ast_sip_session *se
|
|||
snprintf(cause_code->code, data_size - sizeof(*cause_code) + 1, "SIP %d %.*s", status.code,
|
||||
(int) pj_strlen(&status.reason), pj_strbuf(&status.reason));
|
||||
|
||||
cause_code->ast_cause = hangup_sip2cause(status.code);
|
||||
cause_code->ast_cause = ast_sip_hangup_sip2cause(status.code);
|
||||
ast_queue_control_data(session->channel, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
|
||||
ast_channel_hangupcause_hash_set(session->channel, cause_code, data_size);
|
||||
|
||||
|
@ -3213,6 +3158,7 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct
|
|||
pjsip_rdata_sdp_info *sdp = pjsip_rdata_get_sdp_info(rdata);
|
||||
if (sdp && sdp->body.ptr) {
|
||||
ast_trace(-1, "%s: Queueing PROGRESS\n", ast_sip_session_get_name(session));
|
||||
session->early_confirmed = pjsip_100rel_is_reliable(rdata) == PJ_TRUE;
|
||||
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
|
||||
} else {
|
||||
ast_trace(-1, "%s: Queueing RINGING\n", ast_sip_session_get_name(session));
|
||||
|
@ -3233,6 +3179,7 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct
|
|||
ast_trace(-1, "%s: Queueing PROGRESS\n", ast_sip_session_get_name(session));
|
||||
ast_trace(1, "%s Method: %.*s Status: %d Queueing PROGRESS with SDP\n", ast_sip_session_get_name(session),
|
||||
(int)rdata->msg_info.cseq->method.name.slen, rdata->msg_info.cseq->method.name.ptr, status.code);
|
||||
session->early_confirmed = pjsip_100rel_is_reliable(rdata) == PJ_TRUE;
|
||||
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
} else {
|
||||
|
@ -3267,6 +3214,18 @@ static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip
|
|||
SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
|
||||
}
|
||||
|
||||
static int chan_pjsip_incoming_prack(struct ast_sip_session *session, struct pjsip_rx_data *rdata)
|
||||
{
|
||||
SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
|
||||
|
||||
if (pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "PRACK") == 0 &&
|
||||
pjmedia_sdp_neg_get_state(session->inv_session->neg) == PJMEDIA_SDP_NEG_STATE_DONE) {
|
||||
|
||||
session->early_confirmed = 1;
|
||||
}
|
||||
SCOPE_EXIT_RTN_VALUE(0, "%s\n", ast_sip_session_get_name(session));
|
||||
}
|
||||
|
||||
static int update_devstate(void *obj, void *arg, int flags)
|
||||
{
|
||||
ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE,
|
||||
|
@ -3307,6 +3266,8 @@ static struct ast_custom_function session_refresh_function = {
|
|||
.write = pjsip_acf_session_refresh_write,
|
||||
};
|
||||
|
||||
static char *app_pjsip_hangup = "PJSIPHangup";
|
||||
|
||||
/*!
|
||||
* \brief Load the module
|
||||
*
|
||||
|
@ -3364,6 +3325,13 @@ static int load_module(void)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (ast_register_application_xml(app_pjsip_hangup, pjsip_app_hangup)) {
|
||||
ast_log(LOG_WARNING, "Unable to register PJSIPHangup dialplan application\n");
|
||||
goto end;
|
||||
}
|
||||
ast_manager_register_xml(app_pjsip_hangup, EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, pjsip_action_hangup);
|
||||
|
||||
|
||||
ast_sip_register_service(&refer_callback_module);
|
||||
|
||||
ast_sip_session_register_supplement(&chan_pjsip_supplement);
|
||||
|
@ -3379,6 +3347,7 @@ static int load_module(void)
|
|||
ast_sip_session_register_supplement(&call_pickup_supplement);
|
||||
ast_sip_session_register_supplement(&pbx_start_supplement);
|
||||
ast_sip_session_register_supplement(&chan_pjsip_ack_supplement);
|
||||
ast_sip_session_register_supplement(&chan_pjsip_prack_supplement);
|
||||
|
||||
if (pjsip_channel_cli_register()) {
|
||||
ast_log(LOG_ERROR, "Unable to register PJSIP Channel CLI\n");
|
||||
|
@ -3398,6 +3367,7 @@ end:
|
|||
ao2_cleanup(pjsip_uids_onhold);
|
||||
pjsip_uids_onhold = NULL;
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_prack_supplement);
|
||||
ast_sip_session_unregister_supplement(&pbx_start_supplement);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_supplement_response);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
|
||||
|
@ -3409,6 +3379,9 @@ end:
|
|||
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
|
||||
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
|
||||
ast_custom_function_unregister(&session_refresh_function);
|
||||
ast_unregister_application(app_pjsip_hangup);
|
||||
ast_manager_unregister(app_pjsip_hangup);
|
||||
|
||||
ast_channel_unregister(&chan_pjsip_tech);
|
||||
ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
|
||||
|
||||
|
@ -3427,6 +3400,7 @@ static int unload_module(void)
|
|||
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
|
||||
ast_sip_session_unregister_supplement(&pbx_start_supplement);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_prack_supplement);
|
||||
ast_sip_session_unregister_supplement(&call_pickup_supplement);
|
||||
|
||||
ast_sip_unregister_service(&refer_callback_module);
|
||||
|
@ -3437,6 +3411,8 @@ static int unload_module(void)
|
|||
ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
|
||||
ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
|
||||
ast_custom_function_unregister(&session_refresh_function);
|
||||
ast_unregister_application(app_pjsip_hangup);
|
||||
ast_manager_unregister(app_pjsip_hangup);
|
||||
|
||||
ast_channel_unregister(&chan_pjsip_tech);
|
||||
ao2_ref(chan_pjsip_tech.capabilities, -1);
|
||||
|
|
|
@ -129,7 +129,8 @@ static struct ast_format *derive_format_from_cap(struct ast_format_cap *cap)
|
|||
* assignments. Signed linear @ 8kHz does not map, so if that is our
|
||||
* only capability, we force μ-law instead.
|
||||
*/
|
||||
fmt = ast_format_ulaw;
|
||||
ao2_ref(fmt, -1);
|
||||
fmt = ao2_bump(ast_format_ulaw);
|
||||
}
|
||||
|
||||
return fmt;
|
||||
|
@ -211,7 +212,7 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo
|
|||
}
|
||||
|
||||
chan = ast_channel_alloc(1, AST_STATE_DOWN, "", "", "", "", "", assignedids,
|
||||
requestor, 0, "MulticastRTP/%p", instance);
|
||||
requestor, 0, "MulticastRTP/%s-%p", args.destination, instance);
|
||||
if (!chan) {
|
||||
ast_rtp_instance_destroy(instance);
|
||||
goto failure;
|
||||
|
@ -249,6 +250,7 @@ failure:
|
|||
enum {
|
||||
OPT_RTP_CODEC = (1 << 0),
|
||||
OPT_RTP_ENGINE = (1 << 1),
|
||||
OPT_RTP_GLUE = (1 << 2),
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -263,8 +265,14 @@ AST_APP_OPTIONS(unicast_rtp_options, BEGIN_OPTIONS
|
|||
AST_APP_OPTION_ARG('c', OPT_RTP_CODEC, OPT_ARG_RTP_CODEC),
|
||||
/*! Set the RTP engine to use for unicast RTP */
|
||||
AST_APP_OPTION_ARG('e', OPT_RTP_ENGINE, OPT_ARG_RTP_ENGINE),
|
||||
/*! Provide RTP glue for the channel */
|
||||
AST_APP_OPTION('g', OPT_RTP_GLUE),
|
||||
END_OPTIONS );
|
||||
|
||||
static const struct ast_datastore_info chan_rtp_datastore_info = {
|
||||
.type = "CHAN_RTP_GLUE",
|
||||
};
|
||||
|
||||
/*! \brief Function called when we should prepare to call the unicast destination */
|
||||
static struct ast_channel *unicast_rtp_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
|
||||
{
|
||||
|
@ -372,6 +380,13 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
|
|||
|
||||
ast_channel_tech_set(chan, &unicast_rtp_tech);
|
||||
|
||||
if (ast_test_flag(&opts, OPT_RTP_GLUE)) {
|
||||
struct ast_datastore *datastore;
|
||||
if ((datastore = ast_datastore_alloc(&chan_rtp_datastore_info, NULL))) {
|
||||
ast_channel_datastore_add(chan, datastore);
|
||||
}
|
||||
}
|
||||
|
||||
ast_format_cap_append(caps, fmt, 0);
|
||||
ast_channel_nativeformats_set(chan, caps);
|
||||
ast_channel_set_writeformat(chan, fmt);
|
||||
|
@ -381,9 +396,9 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
|
|||
|
||||
ast_channel_tech_pvt_set(chan, instance);
|
||||
|
||||
ast_rtp_instance_get_local_address(instance, &local_address);
|
||||
pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_ADDRESS",
|
||||
ast_sockaddr_stringify_addr(&local_address));
|
||||
ast_rtp_instance_get_local_address(instance, &local_address);
|
||||
pbx_builtin_setvar_helper(chan, "UNICASTRTP_LOCAL_PORT",
|
||||
ast_sockaddr_stringify_port(&local_address));
|
||||
|
||||
|
@ -401,6 +416,61 @@ failure:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*! \brief Function called by RTP engine to get peer capabilities */
|
||||
static void chan_rtp_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
|
||||
{
|
||||
SCOPE_ENTER(1, "%s Native formats %s\n", ast_channel_name(chan),
|
||||
ast_str_tmp(AST_FORMAT_CAP_NAMES_LEN, ast_format_cap_get_names(ast_channel_nativeformats(chan), &STR_TMP)));
|
||||
ast_format_cap_append_from_cap(result, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_UNKNOWN);
|
||||
SCOPE_EXIT_RTN();
|
||||
}
|
||||
|
||||
/*! \brief Function called by RTP engine to change where the remote party should send media.
|
||||
*
|
||||
* chan_rtp is not able to actually update the peer, so this function has no effect.
|
||||
* */
|
||||
static int chan_rtp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*! \brief Function called by RTP engine to get local audio RTP peer */
|
||||
static enum ast_rtp_glue_result chan_rtp_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
|
||||
{
|
||||
return AST_RTP_GLUE_RESULT_FORBID;
|
||||
}
|
||||
|
||||
/*! \brief Function called by RTP engine to get local audio RTP peer */
|
||||
static enum ast_rtp_glue_result chan_rtp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
|
||||
{
|
||||
struct ast_rtp_instance *rtp_instance = ast_channel_tech_pvt(chan);
|
||||
struct ast_datastore *datastore;
|
||||
|
||||
if (!rtp_instance) {
|
||||
return AST_RTP_GLUE_RESULT_FORBID;
|
||||
}
|
||||
|
||||
if ((datastore = ast_channel_datastore_find(chan, &chan_rtp_datastore_info, NULL))) {
|
||||
ao2_ref(datastore, -1);
|
||||
|
||||
*instance = rtp_instance;
|
||||
ao2_ref(*instance, +1);
|
||||
|
||||
return AST_RTP_GLUE_RESULT_LOCAL;
|
||||
}
|
||||
|
||||
return AST_RTP_GLUE_RESULT_FORBID;
|
||||
}
|
||||
|
||||
/*! \brief Local glue for interacting with the RTP engine core */
|
||||
static struct ast_rtp_glue unicast_rtp_glue = {
|
||||
.type = "UnicastRTP",
|
||||
.get_rtp_info = chan_rtp_get_rtp_peer,
|
||||
.get_vrtp_info = chan_rtp_get_vrtp_peer,
|
||||
.get_codec = chan_rtp_get_codec,
|
||||
.update_peer = chan_rtp_set_rtp_peer,
|
||||
};
|
||||
|
||||
/*! \brief Function called when our module is unloaded */
|
||||
static int unload_module(void)
|
||||
{
|
||||
|
@ -412,6 +482,8 @@ static int unload_module(void)
|
|||
ao2_cleanup(unicast_rtp_tech.capabilities);
|
||||
unicast_rtp_tech.capabilities = NULL;
|
||||
|
||||
ast_rtp_glue_unregister(&unicast_rtp_glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,6 +493,9 @@ static int load_module(void)
|
|||
if (!(multicast_rtp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
ast_rtp_glue_register(&unicast_rtp_glue);
|
||||
|
||||
ast_format_cap_append_by_type(multicast_rtp_tech.capabilities, AST_MEDIA_TYPE_UNKNOWN);
|
||||
if (ast_channel_register(&multicast_rtp_tech)) {
|
||||
ast_log(LOG_ERROR, "Unable to register channel class 'MulticastRTP'\n");
|
||||
|
|
|
@ -424,7 +424,7 @@ static void dump_ies(unsigned char *iedata, int len)
|
|||
|
||||
if (len < 2)
|
||||
return;
|
||||
while(len > 2) {
|
||||
while(len >= 2) {
|
||||
ie = iedata[0];
|
||||
ielen = iedata[1];
|
||||
if (ielen + 2> len) {
|
||||
|
@ -1063,7 +1063,7 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
|
|||
if (len == (int)sizeof(unsigned int)) {
|
||||
ies->calling_ani2 = ntohl(get_unaligned_uint32(data + 2));
|
||||
} else {
|
||||
snprintf(tmp, (int)sizeof(tmp), "callingani2 was %d long: %s\n", len, data + 2);
|
||||
snprintf(tmp, sizeof(tmp), "Expected callingani2 to be %zu bytes but was %d\n", sizeof(unsigned int), len);
|
||||
errorf(tmp);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -343,6 +343,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
|
|||
struct ast_sip_session *session;
|
||||
struct ast_sip_session_media *media;
|
||||
struct ast_rtp_instance_stats stats;
|
||||
struct ast_stream *stream;
|
||||
char *print_name = NULL;
|
||||
char *print_time = alloca(32);
|
||||
char codec_in_use[7];
|
||||
|
@ -359,16 +360,29 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
|
|||
|
||||
cpvt = ast_channel_tech_pvt(channel);
|
||||
session = cpvt ? cpvt->session : NULL;
|
||||
if (!session) {
|
||||
|
||||
if (!session
|
||||
|| !session->active_media_state
|
||||
|| !session->active_media_state->topology) {
|
||||
ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
|
||||
ast_channel_unlock(channel);
|
||||
ao2_cleanup(channel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream = ast_stream_topology_get_first_stream_by_type(
|
||||
session->active_media_state->topology, AST_MEDIA_TYPE_AUDIO);
|
||||
|
||||
if (!stream) {
|
||||
ast_str_append(&context->output_buffer, 0, " %s no audio streams\n", snapshot->base->name);
|
||||
ast_channel_unlock(channel);
|
||||
ao2_cleanup(channel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
|
||||
if (!media || !media->rtp) {
|
||||
ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
|
||||
if (!media || media->type != AST_MEDIA_TYPE_AUDIO || !media->rtp) {
|
||||
ast_str_append(&context->output_buffer, 0, " %s corrupted default audio session\n", snapshot->base->name);
|
||||
ast_channel_unlock(channel);
|
||||
ao2_cleanup(channel);
|
||||
return 0;
|
||||
|
|
|
@ -29,508 +29,6 @@
|
|||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<function name="PJSIP_DIAL_CONTACTS" language="en_US">
|
||||
<synopsis>
|
||||
Return a dial string for dialing all contacts on an AOR.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="endpoint" required="true">
|
||||
<para>Name of the endpoint</para>
|
||||
</parameter>
|
||||
<parameter name="aor" required="false">
|
||||
<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
|
||||
</parameter>
|
||||
<parameter name="request_user" required="false">
|
||||
<para>Optional request user to use in the request URI</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_MEDIA_OFFER" language="en_US">
|
||||
<synopsis>
|
||||
Media and codec offerings to be set on an outbound SIP channel prior to dialing.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="media" required="true">
|
||||
<para>types of media offered</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the codecs offered based upon the media choice.</para>
|
||||
<para>When written, sets the codecs to offer when an outbound dial attempt is made,
|
||||
or when a session refresh is sent using <replaceable>PJSIP_SEND_SESSION_REFRESH</replaceable>.
|
||||
</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
|
||||
</see-also>
|
||||
</function>
|
||||
<function name="PJSIP_DTMF_MODE" language="en_US">
|
||||
<since>
|
||||
<version>13.18.0</version>
|
||||
<version>14.7.0</version>
|
||||
<version>15.1.0</version>
|
||||
<version>16.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
Get or change the DTMF mode for a SIP call.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the current DTMF mode</para>
|
||||
<para>When written, sets the current DTMF mode</para>
|
||||
<para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_MOH_PASSTHROUGH" language="en_US">
|
||||
<synopsis>
|
||||
Get or change the on-hold behavior for a SIP call.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the current moh passthrough mode</para>
|
||||
<para>When written, sets the current moh passthrough mode</para>
|
||||
<para>If <replaceable>yes</replaceable>, on-hold re-INVITEs are sent. If <replaceable>no</replaceable>, music on hold is generated.</para>
|
||||
<para>This function can be used to override the moh_passthrough configuration option</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
|
||||
<since>
|
||||
<version>13.12.0</version>
|
||||
<version>14.1.0</version>
|
||||
<version>15.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="update_type" required="false">
|
||||
<para>The type of update to send. Default is <literal>invite</literal>.</para>
|
||||
<enumlist>
|
||||
<enum name="invite">
|
||||
<para>Send the session refresh as a re-INVITE.</para>
|
||||
</enum>
|
||||
<enum name="update">
|
||||
<para>Send the session refresh as an UPDATE.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This function will cause the PJSIP stack to immediately refresh
|
||||
the media session for the channel. This will be done using either a
|
||||
re-INVITE (default) or an UPDATE request.
|
||||
</para>
|
||||
<para>This is most useful when combined with the <replaceable>PJSIP_MEDIA_OFFER</replaceable>
|
||||
dialplan function, as it allows the formats in use on a channel to be
|
||||
re-negotiated after call setup.</para>
|
||||
<warning>
|
||||
<para>The formats the endpoint supports are <emphasis>not</emphasis>
|
||||
checked or enforced by this function. Using this function to offer
|
||||
formats not supported by the endpoint <emphasis>may</emphasis> result
|
||||
in a loss of media.</para>
|
||||
</warning>
|
||||
<example title="Re-negotiate format to g722">
|
||||
; Within some existing extension on an answered channel
|
||||
same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
|
||||
same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
|
||||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="function">PJSIP_MEDIA_OFFER</ref>
|
||||
</see-also>
|
||||
</function>
|
||||
<function name="PJSIP_PARSE_URI" language="en_US">
|
||||
<since>
|
||||
<version>13.24.0</version>
|
||||
<version>16.1.0</version>
|
||||
<version>17.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
Parse an uri and return a type part of the URI.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="uri" required="true">
|
||||
<para>URI to parse</para>
|
||||
</parameter>
|
||||
<parameter name="type" required="true">
|
||||
<para>The <literal>type</literal> parameter specifies which URI part to read</para>
|
||||
<enumlist>
|
||||
<enum name="display">
|
||||
<para>Display name.</para>
|
||||
</enum>
|
||||
<enum name="scheme">
|
||||
<para>URI scheme.</para>
|
||||
</enum>
|
||||
<enum name="user">
|
||||
<para>User part.</para>
|
||||
</enum>
|
||||
<enum name="passwd">
|
||||
<para>Password part.</para>
|
||||
</enum>
|
||||
<enum name="host">
|
||||
<para>Host part.</para>
|
||||
</enum>
|
||||
<enum name="port">
|
||||
<para>Port number, or zero.</para>
|
||||
</enum>
|
||||
<enum name="user_param">
|
||||
<para>User parameter.</para>
|
||||
</enum>
|
||||
<enum name="method_param">
|
||||
<para>Method parameter.</para>
|
||||
</enum>
|
||||
<enum name="transport_param">
|
||||
<para>Transport parameter.</para>
|
||||
</enum>
|
||||
<enum name="ttl_param">
|
||||
<para>TTL param, or -1.</para>
|
||||
</enum>
|
||||
<enum name="lr_param">
|
||||
<para>Loose routing param, or zero.</para>
|
||||
</enum>
|
||||
<enum name="maddr_param">
|
||||
<para>Maddr param.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Parse an URI and return a specified part of the URI.</para>
|
||||
</description>
|
||||
</function>
|
||||
<info name="CHANNEL" language="en_US" tech="PJSIP">
|
||||
<enumlist>
|
||||
<enum name="rtp">
|
||||
<para>R/O Retrieve media related information.</para>
|
||||
<parameter name="type" required="true">
|
||||
<para>When <replaceable>rtp</replaceable> is specified, the
|
||||
<literal>type</literal> parameter must be provided. It specifies
|
||||
which RTP parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="src">
|
||||
<para>Retrieve the local address for RTP.</para>
|
||||
</enum>
|
||||
<enum name="dest">
|
||||
<para>Retrieve the remote address for RTP.</para>
|
||||
</enum>
|
||||
<enum name="direct">
|
||||
<para>If direct media is enabled, this address is the remote address
|
||||
used for RTP.</para>
|
||||
</enum>
|
||||
<enum name="secure">
|
||||
<para>Whether or not the media stream is encrypted.</para>
|
||||
<enumlist>
|
||||
<enum name="0">
|
||||
<para>The media stream is not encrypted.</para>
|
||||
</enum>
|
||||
<enum name="1">
|
||||
<para>The media stream is encrypted.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="hold">
|
||||
<para>Whether or not the media stream is currently restricted
|
||||
due to a call hold.</para>
|
||||
<enumlist>
|
||||
<enum name="0">
|
||||
<para>The media stream is not held.</para>
|
||||
</enum>
|
||||
<enum name="1">
|
||||
<para>The media stream is held.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="media_type" required="false">
|
||||
<para>When <replaceable>rtp</replaceable> is specified, the
|
||||
<literal>media_type</literal> parameter may be provided. It specifies
|
||||
which media stream the chosen RTP parameter should be retrieved
|
||||
from.</para>
|
||||
<enumlist>
|
||||
<enum name="audio">
|
||||
<para>Retrieve information from the audio media stream.</para>
|
||||
<note><para>If not specified, <literal>audio</literal> is used
|
||||
by default.</para></note>
|
||||
</enum>
|
||||
<enum name="video">
|
||||
<para>Retrieve information from the video media stream.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
<enum name="rtcp">
|
||||
<para>R/O Retrieve RTCP statistics.</para>
|
||||
<parameter name="statistic" required="true">
|
||||
<para>When <replaceable>rtcp</replaceable> is specified, the
|
||||
<literal>statistic</literal> parameter must be provided. It specifies
|
||||
which RTCP statistic parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="all">
|
||||
<para>Retrieve a summary of all RTCP statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="ssrc">
|
||||
<para>Our Synchronization Source identifier</para>
|
||||
</enum>
|
||||
<enum name="themssrc">
|
||||
<para>Their Synchronization Source identifier</para>
|
||||
</enum>
|
||||
<enum name="lp">
|
||||
<para>Our lost packet count</para>
|
||||
</enum>
|
||||
<enum name="rxjitter">
|
||||
<para>Received packet jitter</para>
|
||||
</enum>
|
||||
<enum name="rxcount">
|
||||
<para>Received packet count</para>
|
||||
</enum>
|
||||
<enum name="txjitter">
|
||||
<para>Transmitted packet jitter</para>
|
||||
</enum>
|
||||
<enum name="txcount">
|
||||
<para>Transmitted packet count</para>
|
||||
</enum>
|
||||
<enum name="rlp">
|
||||
<para>Remote lost packet count</para>
|
||||
</enum>
|
||||
<enum name="rtt">
|
||||
<para>Round trip time</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_jitter">
|
||||
<para>Retrieve a summary of all RTCP Jitter statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrxjitter">
|
||||
<para>Our minimum jitter</para>
|
||||
</enum>
|
||||
<enum name="maxrxjitter">
|
||||
<para>Our max jitter</para>
|
||||
</enum>
|
||||
<enum name="avgrxjitter">
|
||||
<para>Our average jitter</para>
|
||||
</enum>
|
||||
<enum name="stdevrxjitter">
|
||||
<para>Our jitter standard deviation</para>
|
||||
</enum>
|
||||
<enum name="reported_minjitter">
|
||||
<para>Their minimum jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_maxjitter">
|
||||
<para>Their max jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_avgjitter">
|
||||
<para>Their average jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_stdevjitter">
|
||||
<para>Their jitter standard deviation</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_loss">
|
||||
<para>Retrieve a summary of all RTCP packet loss statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrxlost">
|
||||
<para>Our minimum lost packets</para>
|
||||
</enum>
|
||||
<enum name="maxrxlost">
|
||||
<para>Our max lost packets</para>
|
||||
</enum>
|
||||
<enum name="avgrxlost">
|
||||
<para>Our average lost packets</para>
|
||||
</enum>
|
||||
<enum name="stdevrxlost">
|
||||
<para>Our lost packets standard deviation</para>
|
||||
</enum>
|
||||
<enum name="reported_minlost">
|
||||
<para>Their minimum lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_maxlost">
|
||||
<para>Their max lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_avglost">
|
||||
<para>Their average lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_stdevlost">
|
||||
<para>Their lost packets standard deviation</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_rtt">
|
||||
<para>Retrieve a summary of all RTCP round trip time information.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrtt">
|
||||
<para>Minimum round trip time</para>
|
||||
</enum>
|
||||
<enum name="maxrtt">
|
||||
<para>Maximum round trip time</para>
|
||||
</enum>
|
||||
<enum name="avgrtt">
|
||||
<para>Average round trip time</para>
|
||||
</enum>
|
||||
<enum name="stdevrtt">
|
||||
<para>Standard deviation round trip time</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="txcount"><para>Transmitted packet count</para></enum>
|
||||
<enum name="rxcount"><para>Received packet count</para></enum>
|
||||
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
|
||||
<enum name="rxjitter"><para>Received packet jitter</para></enum>
|
||||
<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
|
||||
<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
|
||||
<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
|
||||
<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
|
||||
<enum name="local_maxjitter"><para>Our max jitter</para></enum>
|
||||
<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
|
||||
<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
|
||||
<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
|
||||
<enum name="txploss"><para>Transmitted packet loss</para></enum>
|
||||
<enum name="rxploss"><para>Received packet loss</para></enum>
|
||||
<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
|
||||
<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
|
||||
<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
|
||||
<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
|
||||
<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
|
||||
<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
|
||||
<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
|
||||
<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
|
||||
<enum name="rtt"><para>Round trip time</para></enum>
|
||||
<enum name="maxrtt"><para>Maximum round trip time</para></enum>
|
||||
<enum name="minrtt"><para>Minimum round trip time</para></enum>
|
||||
<enum name="normdevrtt"><para>Average round trip time</para></enum>
|
||||
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
|
||||
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
|
||||
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="media_type" required="false">
|
||||
<para>When <replaceable>rtcp</replaceable> is specified, the
|
||||
<literal>media_type</literal> parameter may be provided. It specifies
|
||||
which media stream the chosen RTCP parameter should be retrieved
|
||||
from.</para>
|
||||
<enumlist>
|
||||
<enum name="audio">
|
||||
<para>Retrieve information from the audio media stream.</para>
|
||||
<note><para>If not specified, <literal>audio</literal> is used
|
||||
by default.</para></note>
|
||||
</enum>
|
||||
<enum name="video">
|
||||
<para>Retrieve information from the video media stream.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
<enum name="endpoint">
|
||||
<para>R/O The name of the endpoint associated with this channel.
|
||||
Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
|
||||
further endpoint related information.</para>
|
||||
</enum>
|
||||
<enum name="contact">
|
||||
<para>R/O The name of the contact associated with this channel.
|
||||
Use the <replaceable>PJSIP_CONTACT</replaceable> function to obtain
|
||||
further contact related information. Note this may not be present and if so
|
||||
is only available on outgoing legs.</para>
|
||||
</enum>
|
||||
<enum name="aor">
|
||||
<para>R/O The name of the AOR associated with this channel.
|
||||
Use the <replaceable>PJSIP_AOR</replaceable> function to obtain
|
||||
further AOR related information. Note this may not be present and if so
|
||||
is only available on outgoing legs.</para>
|
||||
</enum>
|
||||
<enum name="pjsip">
|
||||
<para>R/O Obtain information about the current PJSIP channel and its
|
||||
session.</para>
|
||||
<parameter name="type" required="true">
|
||||
<para>When <replaceable>pjsip</replaceable> is specified, the
|
||||
<literal>type</literal> parameter must be provided. It specifies
|
||||
which signalling parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="call-id">
|
||||
<para>The SIP call-id.</para>
|
||||
</enum>
|
||||
<enum name="secure">
|
||||
<para>Whether or not the signalling uses a secure transport.</para>
|
||||
<enumlist>
|
||||
<enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
|
||||
<enum name="1"><para>The signalling uses a secure transport.</para></enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="target_uri">
|
||||
<para>The contact URI where requests are sent.</para>
|
||||
</enum>
|
||||
<enum name="local_uri">
|
||||
<para>The local URI.</para>
|
||||
</enum>
|
||||
<enum name="local_tag">
|
||||
<para>Tag in From header</para>
|
||||
</enum>
|
||||
<enum name="remote_uri">
|
||||
<para>The remote URI.</para>
|
||||
</enum>
|
||||
<enum name="remote_tag">
|
||||
<para>Tag in To header</para>
|
||||
</enum>
|
||||
<enum name="request_uri">
|
||||
<para>The request URI of the incoming <literal>INVITE</literal>
|
||||
associated with the creation of this channel.</para>
|
||||
</enum>
|
||||
<enum name="t38state">
|
||||
<para>The current state of any T.38 fax on this channel.</para>
|
||||
<enumlist>
|
||||
<enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
|
||||
<enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
|
||||
<enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
|
||||
<enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
|
||||
<enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="local_addr">
|
||||
<para>On inbound calls, the full IP address and port number that
|
||||
the <literal>INVITE</literal> request was received on. On outbound
|
||||
calls, the full IP address and port number that the <literal>INVITE</literal>
|
||||
request was transmitted from.</para>
|
||||
</enum>
|
||||
<enum name="remote_addr">
|
||||
<para>On inbound calls, the full IP address and port number that
|
||||
the <literal>INVITE</literal> request was received from. On outbound
|
||||
calls, the full IP address and port number that the <literal>INVITE</literal>
|
||||
request was transmitted to.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
<info name="CHANNEL_EXAMPLES" language="en_US" tech="PJSIP">
|
||||
<example title="PJSIP specific CHANNEL examples">
|
||||
; Log the current Call-ID
|
||||
same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
|
||||
|
||||
; Log the destination address of the audio stream
|
||||
same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
|
||||
|
||||
; Store the round-trip time associated with a
|
||||
; video stream in the CDR field video-rtt
|
||||
same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
|
||||
</example>
|
||||
</info>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <pjsip.h>
|
||||
|
@ -541,6 +39,7 @@
|
|||
#include "asterisk/module.h"
|
||||
#include "asterisk/acl.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/conversions.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/stream.h"
|
||||
#include "asterisk/format.h"
|
||||
|
@ -678,6 +177,8 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
|
|||
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_RTT;
|
||||
} else if (!strcasecmp(type, "all_loss")) {
|
||||
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_LOSS;
|
||||
} else if (!strcasecmp(type, "all_mes")) {
|
||||
stat_field = AST_RTP_INSTANCE_STAT_FIELD_QUALITY_MES;
|
||||
}
|
||||
|
||||
if (!ast_rtp_instance_get_quality(media->rtp, stat_field, buf, buflen)) {
|
||||
|
@ -724,6 +225,16 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c
|
|||
{ "stdevrtt", DBL, { .d8 = &stats.stdevrtt, }, },
|
||||
{ "local_ssrc", INT, { .i4 = &stats.local_ssrc, }, },
|
||||
{ "remote_ssrc", INT, { .i4 = &stats.remote_ssrc, }, },
|
||||
{ "txmes", DBL, { .d8 = &stats.txmes, }, },
|
||||
{ "rxmes", DBL, { .d8 = &stats.rxmes, }, },
|
||||
{ "remote_maxmes", DBL, { .d8 = &stats.remote_maxmes, }, },
|
||||
{ "remote_minmes", DBL, { .d8 = &stats.remote_minmes, }, },
|
||||
{ "remote_normdevmes", DBL, { .d8 = &stats.remote_normdevmes, }, },
|
||||
{ "remote_stdevmes", DBL, { .d8 = &stats.remote_stdevmes, }, },
|
||||
{ "local_maxmes", DBL, { .d8 = &stats.local_maxmes, }, },
|
||||
{ "local_minmes", DBL, { .d8 = &stats.local_minmes, }, },
|
||||
{ "local_normdevmes", DBL, { .d8 = &stats.local_normdevmes, }, },
|
||||
{ "local_stdevmes", DBL, { .d8 = &stats.local_stdevmes, }, },
|
||||
{ NULL, },
|
||||
};
|
||||
|
||||
|
@ -1717,3 +1228,121 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c
|
|||
|
||||
return ast_sip_push_task_wait_serializer(channel->session->serializer, refresh_write_cb, &rdata);
|
||||
}
|
||||
|
||||
struct hangup_data {
|
||||
struct ast_sip_session *session;
|
||||
int response_code;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Serializer task to hangup channel
|
||||
*/
|
||||
static int pjsip_hangup(void *obj)
|
||||
{
|
||||
struct hangup_data *hdata = obj;
|
||||
pjsip_tx_data *packet = NULL;
|
||||
|
||||
if ((hdata->session->inv_session->state != PJSIP_INV_STATE_DISCONNECTED) &&
|
||||
(pjsip_inv_answer(hdata->session->inv_session, hdata->response_code, NULL, NULL, &packet) == PJ_SUCCESS)) {
|
||||
ast_sip_session_send_response(hdata->session, packet);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Callback that validates the response code
|
||||
*/
|
||||
static int response_code_validator(const char *channel_name,
|
||||
const char *response) {
|
||||
int response_code;
|
||||
|
||||
int rc = ast_str_to_int(response, &response_code);
|
||||
if (rc != 0) {
|
||||
response_code = ast_sip_str2rc(response);
|
||||
if (response_code < 0) {
|
||||
ast_log(LOG_WARNING, "%s: Unrecognized response code parameter '%s'."
|
||||
" Defaulting to 603 DECLINE\n",
|
||||
channel_name, response);
|
||||
return PJSIP_SC_DECLINE;
|
||||
}
|
||||
}
|
||||
|
||||
if (response_code < 400 || response_code > 699) {
|
||||
ast_log(LOG_WARNING, "%s: Response code %d is out of range 400 -> 699."
|
||||
" Defaulting to 603 DECLINE\n",
|
||||
channel_name, response_code);
|
||||
return PJSIP_SC_DECLINE;
|
||||
}
|
||||
return response_code;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Called by pjsip_app_hangup and pjsip_action_hangup
|
||||
* to actually perform the hangup
|
||||
*/
|
||||
static void pjsip_app_hangup_handler(struct ast_channel *chan, int response_code)
|
||||
{
|
||||
struct ast_sip_channel_pvt *channel;
|
||||
struct hangup_data hdata = { NULL, -1 };
|
||||
const char *tag = ast_channel_name(chan);
|
||||
|
||||
hdata.response_code = response_code;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (strcmp(ast_channel_tech(chan)->type, "PJSIP")) {
|
||||
ast_log(LOG_WARNING, "%s: Not a PJSIP channel\n", tag);
|
||||
ast_channel_unlock(chan);
|
||||
return;
|
||||
}
|
||||
|
||||
channel = ast_channel_tech_pvt(chan);
|
||||
hdata.session = channel->session;
|
||||
|
||||
if (hdata.session->inv_session->role != PJSIP_ROLE_UAS || (
|
||||
hdata.session->inv_session->state != PJSIP_INV_STATE_INCOMING &&
|
||||
hdata.session->inv_session->state != PJSIP_INV_STATE_EARLY)) {
|
||||
ast_log(LOG_WARNING, "%s: Not an incoming channel or invalid state '%s'\n",
|
||||
tag, pjsip_inv_state_name(hdata.session->inv_session->state));
|
||||
ast_channel_unlock(chan);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (ast_sip_push_task_wait_serializer(channel->session->serializer,
|
||||
pjsip_hangup, &hdata) != 0) {
|
||||
ast_log(LOG_WARNING, "%s: failed to push hangup task to serializer\n", tag);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief PJSIPHangup Dialplan App
|
||||
*/
|
||||
int pjsip_app_hangup(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
int response_code;
|
||||
const char *tag = ast_channel_name(chan);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "%s: Missing response code parameter\n", tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
response_code = response_code_validator(tag, data);
|
||||
|
||||
pjsip_app_hangup_handler(chan, response_code);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief PJSIPHangup Manager Action
|
||||
*/
|
||||
int pjsip_action_hangup(struct mansession *s, const struct message *m)
|
||||
{
|
||||
return ast_manager_hangup_helper(s, m,
|
||||
pjsip_app_hangup_handler, response_code_validator);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,659 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE docs SYSTEM "appdocsxml.dtd">
|
||||
<docs>
|
||||
<application name="PJSIPHangup" language="en_US">
|
||||
<synopsis>
|
||||
Hangup an incoming PJSIP channel with a SIP response code
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="Cause" required="true">
|
||||
<para>May be one of...</para>
|
||||
<enumlist>
|
||||
<enum name="Response code"><para>A numeric response code in the range 400 ->699</para></enum>
|
||||
<enum name="Response code name"><para>A response code name from
|
||||
<literal>third-party/pjproject/source/pjsip/include/pjsip/sip_msg.h</literal>
|
||||
such as <literal>USE_IDENTITY_HEADER</literal> or
|
||||
<literal>PJSIP_SC_USE_IDENTITY_HEADER</literal></para></enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>
|
||||
Hangs up an incoming PJSIP channel and returns the
|
||||
specified SIP response code in the final response to the caller.
|
||||
</para>
|
||||
<para>
|
||||
</para>
|
||||
<warning><para>
|
||||
This function must be called BEFORE anything that
|
||||
might cause any other final (non 1XX) response to be sent.
|
||||
For example calling <literal>Answer()</literal> or
|
||||
<literal>Playback</literal> without the
|
||||
<literal>noanswer</literal> option will cause the call
|
||||
to be answered and a final 200 response to be sent.
|
||||
</para></warning>
|
||||
<para>
|
||||
</para>
|
||||
<para>As with the <literal>Hangup</literal> application,
|
||||
the dialplan will terminate after calling this function.</para>
|
||||
<para>
|
||||
</para>
|
||||
<para>The cause code set on the channel will be translated to
|
||||
a standard ISDN cause code using the table defined in
|
||||
ast_sip_hangup_sip2cause() in res_pjsip.c</para>
|
||||
<para>
|
||||
</para>
|
||||
<example title="Terminate call with 437 response code">
|
||||
same = n,PJSIPHangup(437)
|
||||
</example>
|
||||
<example title="Terminate call with 437 response code using the response code name">
|
||||
same = n,PJSIPHangup(UNSUPPORTED_CERTIFICATE)
|
||||
</example>
|
||||
<example title="Terminate call with 437 response code based on condition">
|
||||
same = n,ExecIf($[${SOMEVALUE} = ${SOME_BAD_VALUE}]?PJSIPHangup(437))
|
||||
</example>
|
||||
</description>
|
||||
</application>
|
||||
|
||||
<manager name="PJSIPHangup" language="en_US">
|
||||
<synopsis>
|
||||
Hangup an incoming PJSIP channel with a SIP response code
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
||||
<xi:include xpointer="xpointer(/docs/manager[@name='Hangup']/syntax/parameter[@name='Channel'])" />
|
||||
<xi:include xpointer="xpointer(/docs/application[@name='PJSIPHangup']/syntax/parameter[@name='Cause'])" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>
|
||||
Hangs up an incoming PJSIP channel and returns the
|
||||
specified SIP response code in the final response to the caller.
|
||||
</para>
|
||||
<para>
|
||||
</para>
|
||||
<warning><para>
|
||||
This function must be called BEFORE anything that
|
||||
might cause any other final (non 1XX) response to be sent.
|
||||
For example calling <literal>Answer()</literal> or
|
||||
<literal>Playback</literal> without the
|
||||
<literal>noanswer</literal> option will cause the call
|
||||
to be answered and a final 200 response to be sent.
|
||||
</para></warning>
|
||||
<para>
|
||||
</para>
|
||||
<para>The cause code set on the channel will be translated to
|
||||
a standard ISDN cause code using the table defined in
|
||||
ast_sip_hangup_sip2cause() in res_pjsip.c</para>
|
||||
<para>
|
||||
</para>
|
||||
<example title="Terminate call with 437 response code">
|
||||
Action: PJSIPHangup
|
||||
ActionID: 12345678
|
||||
Channel: PJSIP/alice-00000002
|
||||
Cause: 437
|
||||
</example>
|
||||
<example title="Terminate call with 437 response code using the response code name">
|
||||
Action: PJSIPHangup
|
||||
ActionID: 12345678
|
||||
Channel: PJSIP/alice-00000002
|
||||
Cause: UNSUPPORTED_CERTIFICATE
|
||||
</example>
|
||||
</description>
|
||||
</manager>
|
||||
|
||||
<function name="PJSIP_DIAL_CONTACTS" language="en_US">
|
||||
<synopsis>
|
||||
Return a dial string for dialing all contacts on an AOR.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="endpoint" required="true">
|
||||
<para>Name of the endpoint</para>
|
||||
</parameter>
|
||||
<parameter name="aor" required="false">
|
||||
<para>Name of an AOR to use, if not specified the configured AORs on the endpoint are used</para>
|
||||
</parameter>
|
||||
<parameter name="request_user" required="false">
|
||||
<para>Optional request user to use in the request URI</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Returns a properly formatted dial string for dialing all contacts on an AOR.</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_MEDIA_OFFER" language="en_US">
|
||||
<synopsis>
|
||||
Media and codec offerings to be set on an outbound SIP channel prior to dialing.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="media" required="true">
|
||||
<para>types of media offered</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the codecs offered based upon the media choice.</para>
|
||||
<para>When written, sets the codecs to offer when an outbound dial attempt is made,
|
||||
or when a session refresh is sent using <replaceable>PJSIP_SEND_SESSION_REFRESH</replaceable>.
|
||||
</para>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="function">PJSIP_SEND_SESSION_REFRESH</ref>
|
||||
</see-also>
|
||||
</function>
|
||||
<function name="PJSIP_DTMF_MODE" language="en_US">
|
||||
<since>
|
||||
<version>13.18.0</version>
|
||||
<version>14.7.0</version>
|
||||
<version>15.1.0</version>
|
||||
<version>16.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
Get or change the DTMF mode for a SIP call.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the current DTMF mode</para>
|
||||
<para>When written, sets the current DTMF mode</para>
|
||||
<para>This function uses the same DTMF mode naming as the dtmf_mode configuration option</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_MOH_PASSTHROUGH" language="en_US">
|
||||
<synopsis>
|
||||
Get or change the on-hold behavior for a SIP call.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>When read, returns the current moh passthrough mode</para>
|
||||
<para>When written, sets the current moh passthrough mode</para>
|
||||
<para>If <replaceable>yes</replaceable>, on-hold re-INVITEs are sent. If <replaceable>no</replaceable>, music on hold is generated.</para>
|
||||
<para>This function can be used to override the moh_passthrough configuration option</para>
|
||||
</description>
|
||||
</function>
|
||||
<function name="PJSIP_SEND_SESSION_REFRESH" language="en_US">
|
||||
<since>
|
||||
<version>13.12.0</version>
|
||||
<version>14.1.0</version>
|
||||
<version>15.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
W/O: Initiate a session refresh via an UPDATE or re-INVITE on an established media session
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="update_type" required="false">
|
||||
<para>The type of update to send. Default is <literal>invite</literal>.</para>
|
||||
<enumlist>
|
||||
<enum name="invite">
|
||||
<para>Send the session refresh as a re-INVITE.</para>
|
||||
</enum>
|
||||
<enum name="update">
|
||||
<para>Send the session refresh as an UPDATE.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>This function will cause the PJSIP stack to immediately refresh
|
||||
the media session for the channel. This will be done using either a
|
||||
re-INVITE (default) or an UPDATE request.
|
||||
</para>
|
||||
<para>This is most useful when combined with the <replaceable>PJSIP_MEDIA_OFFER</replaceable>
|
||||
dialplan function, as it allows the formats in use on a channel to be
|
||||
re-negotiated after call setup.</para>
|
||||
<warning>
|
||||
<para>The formats the endpoint supports are <emphasis>not</emphasis>
|
||||
checked or enforced by this function. Using this function to offer
|
||||
formats not supported by the endpoint <emphasis>may</emphasis> result
|
||||
in a loss of media.</para>
|
||||
</warning>
|
||||
<example title="Re-negotiate format to g722">
|
||||
; Within some existing extension on an answered channel
|
||||
same => n,Set(PJSIP_MEDIA_OFFER(audio)=!all,g722)
|
||||
same => n,Set(PJSIP_SEND_SESSION_REFRESH()=invite)
|
||||
</example>
|
||||
</description>
|
||||
<see-also>
|
||||
<ref type="function">PJSIP_MEDIA_OFFER</ref>
|
||||
</see-also>
|
||||
</function>
|
||||
<function name="PJSIP_PARSE_URI" language="en_US">
|
||||
<since>
|
||||
<version>13.24.0</version>
|
||||
<version>16.1.0</version>
|
||||
<version>17.0.0</version>
|
||||
</since>
|
||||
<synopsis>
|
||||
Parse an uri and return a type part of the URI.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="uri" required="true">
|
||||
<para>URI to parse</para>
|
||||
</parameter>
|
||||
<parameter name="type" required="true">
|
||||
<para>The <literal>type</literal> parameter specifies which URI part to read</para>
|
||||
<enumlist>
|
||||
<enum name="display">
|
||||
<para>Display name.</para>
|
||||
</enum>
|
||||
<enum name="scheme">
|
||||
<para>URI scheme.</para>
|
||||
</enum>
|
||||
<enum name="user">
|
||||
<para>User part.</para>
|
||||
</enum>
|
||||
<enum name="passwd">
|
||||
<para>Password part.</para>
|
||||
</enum>
|
||||
<enum name="host">
|
||||
<para>Host part.</para>
|
||||
</enum>
|
||||
<enum name="port">
|
||||
<para>Port number, or zero.</para>
|
||||
</enum>
|
||||
<enum name="user_param">
|
||||
<para>User parameter.</para>
|
||||
</enum>
|
||||
<enum name="method_param">
|
||||
<para>Method parameter.</para>
|
||||
</enum>
|
||||
<enum name="transport_param">
|
||||
<para>Transport parameter.</para>
|
||||
</enum>
|
||||
<enum name="ttl_param">
|
||||
<para>TTL param, or -1.</para>
|
||||
</enum>
|
||||
<enum name="lr_param">
|
||||
<para>Loose routing param, or zero.</para>
|
||||
</enum>
|
||||
<enum name="maddr_param">
|
||||
<para>Maddr param.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Parse an URI and return a specified part of the URI.</para>
|
||||
</description>
|
||||
</function>
|
||||
|
||||
<info name="CHANNEL" language="en_US" tech="PJSIP">
|
||||
<enumlist>
|
||||
<enum name="rtp">
|
||||
<para>R/O Retrieve media related information.</para>
|
||||
<parameter name="type" required="true">
|
||||
<para>When <replaceable>rtp</replaceable> is specified, the
|
||||
<literal>type</literal> parameter must be provided. It specifies
|
||||
which RTP parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="src">
|
||||
<para>Retrieve the local address for RTP.</para>
|
||||
</enum>
|
||||
<enum name="dest">
|
||||
<para>Retrieve the remote address for RTP.</para>
|
||||
</enum>
|
||||
<enum name="direct">
|
||||
<para>If direct media is enabled, this address is the remote address
|
||||
used for RTP.</para>
|
||||
</enum>
|
||||
<enum name="secure">
|
||||
<para>Whether or not the media stream is encrypted.</para>
|
||||
<enumlist>
|
||||
<enum name="0">
|
||||
<para>The media stream is not encrypted.</para>
|
||||
</enum>
|
||||
<enum name="1">
|
||||
<para>The media stream is encrypted.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="hold">
|
||||
<para>Whether or not the media stream is currently restricted
|
||||
due to a call hold.</para>
|
||||
<enumlist>
|
||||
<enum name="0">
|
||||
<para>The media stream is not held.</para>
|
||||
</enum>
|
||||
<enum name="1">
|
||||
<para>The media stream is held.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="media_type" required="false">
|
||||
<para>When <replaceable>rtp</replaceable> is specified, the
|
||||
<literal>media_type</literal> parameter may be provided. It specifies
|
||||
which media stream the chosen RTP parameter should be retrieved
|
||||
from.</para>
|
||||
<enumlist>
|
||||
<enum name="audio">
|
||||
<para>Retrieve information from the audio media stream.</para>
|
||||
<note><para>If not specified, <literal>audio</literal> is used
|
||||
by default.</para></note>
|
||||
</enum>
|
||||
<enum name="video">
|
||||
<para>Retrieve information from the video media stream.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
<enum name="rtcp">
|
||||
<para>R/O Retrieve RTCP statistics.</para>
|
||||
<parameter name="statistic" required="true">
|
||||
<para>When <replaceable>rtcp</replaceable> is specified, the
|
||||
<literal>statistic</literal> parameter must be provided. It specifies
|
||||
which RTCP statistic parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="all">
|
||||
<para>Retrieve a summary of all RTCP statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="ssrc">
|
||||
<para>Our Synchronization Source identifier</para>
|
||||
</enum>
|
||||
<enum name="themssrc">
|
||||
<para>Their Synchronization Source identifier</para>
|
||||
</enum>
|
||||
<enum name="lp">
|
||||
<para>Our lost packet count</para>
|
||||
</enum>
|
||||
<enum name="rxjitter">
|
||||
<para>Received packet jitter</para>
|
||||
</enum>
|
||||
<enum name="rxcount">
|
||||
<para>Received packet count</para>
|
||||
</enum>
|
||||
<enum name="txjitter">
|
||||
<para>Transmitted packet jitter</para>
|
||||
</enum>
|
||||
<enum name="txcount">
|
||||
<para>Transmitted packet count</para>
|
||||
</enum>
|
||||
<enum name="rlp">
|
||||
<para>Remote lost packet count</para>
|
||||
</enum>
|
||||
<enum name="rtt">
|
||||
<para>Round trip time</para>
|
||||
</enum>
|
||||
<enum name="txmes">
|
||||
<para>Transmitted Media Experience Score</para>
|
||||
</enum>
|
||||
<enum name="rxmes">
|
||||
<para>Received Media Experience Score</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_jitter">
|
||||
<para>Retrieve a summary of all RTCP Jitter statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrxjitter">
|
||||
<para>Our minimum jitter</para>
|
||||
</enum>
|
||||
<enum name="maxrxjitter">
|
||||
<para>Our max jitter</para>
|
||||
</enum>
|
||||
<enum name="avgrxjitter">
|
||||
<para>Our average jitter</para>
|
||||
</enum>
|
||||
<enum name="stdevrxjitter">
|
||||
<para>Our jitter standard deviation</para>
|
||||
</enum>
|
||||
<enum name="reported_minjitter">
|
||||
<para>Their minimum jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_maxjitter">
|
||||
<para>Their max jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_avgjitter">
|
||||
<para>Their average jitter</para>
|
||||
</enum>
|
||||
<enum name="reported_stdevjitter">
|
||||
<para>Their jitter standard deviation</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_loss">
|
||||
<para>Retrieve a summary of all RTCP packet loss statistics.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrxlost">
|
||||
<para>Our minimum lost packets</para>
|
||||
</enum>
|
||||
<enum name="maxrxlost">
|
||||
<para>Our max lost packets</para>
|
||||
</enum>
|
||||
<enum name="avgrxlost">
|
||||
<para>Our average lost packets</para>
|
||||
</enum>
|
||||
<enum name="stdevrxlost">
|
||||
<para>Our lost packets standard deviation</para>
|
||||
</enum>
|
||||
<enum name="reported_minlost">
|
||||
<para>Their minimum lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_maxlost">
|
||||
<para>Their max lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_avglost">
|
||||
<para>Their average lost packets</para>
|
||||
</enum>
|
||||
<enum name="reported_stdevlost">
|
||||
<para>Their lost packets standard deviation</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_rtt">
|
||||
<para>Retrieve a summary of all RTCP round trip time information.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minrtt">
|
||||
<para>Minimum round trip time</para>
|
||||
</enum>
|
||||
<enum name="maxrtt">
|
||||
<para>Maximum round trip time</para>
|
||||
</enum>
|
||||
<enum name="avgrtt">
|
||||
<para>Average round trip time</para>
|
||||
</enum>
|
||||
<enum name="stdevrtt">
|
||||
<para>Standard deviation round trip time</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="all_mes">
|
||||
<para>Retrieve a summary of all RTCP Media Experience Score information.</para>
|
||||
<para>The following data items are returned in a semi-colon
|
||||
delineated list:</para>
|
||||
<enumlist>
|
||||
<enum name="minmes">
|
||||
<para>Minimum MES based on us analysing received packets.</para>
|
||||
</enum>
|
||||
<enum name="maxmes">
|
||||
<para>Maximum MES based on us analysing received packets.</para>
|
||||
</enum>
|
||||
<enum name="avgmes">
|
||||
<para>Average MES based on us analysing received packets.</para>
|
||||
</enum>
|
||||
<enum name="stdevmes">
|
||||
<para>Standard deviation MES based on us analysing received packets.</para>
|
||||
</enum>
|
||||
<enum name="reported_minmes">
|
||||
<para>Minimum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
|
||||
</enum>
|
||||
<enum name="reported_maxmes">
|
||||
<para>Maximum MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
|
||||
</enum>
|
||||
<enum name="reported_avgmes">
|
||||
<para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
|
||||
</enum>
|
||||
<enum name="reported_stdevmes">
|
||||
<para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="txcount"><para>Transmitted packet count</para></enum>
|
||||
<enum name="rxcount"><para>Received packet count</para></enum>
|
||||
<enum name="txjitter"><para>Transmitted packet jitter</para></enum>
|
||||
<enum name="rxjitter"><para>Received packet jitter</para></enum>
|
||||
<enum name="remote_maxjitter"><para>Their max jitter</para></enum>
|
||||
<enum name="remote_minjitter"><para>Their minimum jitter</para></enum>
|
||||
<enum name="remote_normdevjitter"><para>Their average jitter</para></enum>
|
||||
<enum name="remote_stdevjitter"><para>Their jitter standard deviation</para></enum>
|
||||
<enum name="local_maxjitter"><para>Our max jitter</para></enum>
|
||||
<enum name="local_minjitter"><para>Our minimum jitter</para></enum>
|
||||
<enum name="local_normdevjitter"><para>Our average jitter</para></enum>
|
||||
<enum name="local_stdevjitter"><para>Our jitter standard deviation</para></enum>
|
||||
<enum name="txploss"><para>Transmitted packet loss</para></enum>
|
||||
<enum name="rxploss"><para>Received packet loss</para></enum>
|
||||
<enum name="remote_maxrxploss"><para>Their max lost packets</para></enum>
|
||||
<enum name="remote_minrxploss"><para>Their minimum lost packets</para></enum>
|
||||
<enum name="remote_normdevrxploss"><para>Their average lost packets</para></enum>
|
||||
<enum name="remote_stdevrxploss"><para>Their lost packets standard deviation</para></enum>
|
||||
<enum name="local_maxrxploss"><para>Our max lost packets</para></enum>
|
||||
<enum name="local_minrxploss"><para>Our minimum lost packets</para></enum>
|
||||
<enum name="local_normdevrxploss"><para>Our average lost packets</para></enum>
|
||||
<enum name="local_stdevrxploss"><para>Our lost packets standard deviation</para></enum>
|
||||
<enum name="rtt"><para>Round trip time</para></enum>
|
||||
<enum name="maxrtt"><para>Maximum round trip time</para></enum>
|
||||
<enum name="minrtt"><para>Minimum round trip time</para></enum>
|
||||
<enum name="normdevrtt"><para>Average round trip time</para></enum>
|
||||
<enum name="stdevrtt"><para>Standard deviation round trip time</para></enum>
|
||||
<enum name="local_ssrc"><para>Our Synchronization Source identifier</para></enum>
|
||||
<enum name="remote_ssrc"><para>Their Synchronization Source identifier</para></enum>
|
||||
<enum name="txmes"><para>
|
||||
Current MES based on us analyzing rtt, jitter and loss
|
||||
in the actual received RTP stream received from the remote end.
|
||||
I.E. This is the MES for the incoming audio stream.
|
||||
</para></enum>
|
||||
<enum name="rxmes"><para>
|
||||
Current MES based on rtt and the jitter and loss values in
|
||||
RTCP sender and receiver reports we receive from the
|
||||
remote end. I.E. This is the MES for the outgoing audio stream.
|
||||
</para></enum>
|
||||
<enum name="remote_maxmes"><para>Max MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
|
||||
<enum name="remote_minmes"><para>Min MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
|
||||
<enum name="remote_normdevmes"><para>Average MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
|
||||
<enum name="remote_stdevmes"><para>Standard deviation MES based on data we get in Sender and Receiver Reports sent by the remote end</para></enum>
|
||||
<enum name="local_maxmes"><para>Max MES based on us analyzing the received RTP stream</para></enum>
|
||||
<enum name="local_minmes"><para>Min MES based on us analyzing the received RTP stream</para></enum>
|
||||
<enum name="local_normdevmes"><para>Average MES based on us analyzing the received RTP stream</para></enum>
|
||||
<enum name="local_stdevmes"><para>Standard deviation MES based on us analyzing the received RTP stream</para></enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="media_type" required="false">
|
||||
<para>When <replaceable>rtcp</replaceable> is specified, the
|
||||
<literal>media_type</literal> parameter may be provided. It specifies
|
||||
which media stream the chosen RTCP parameter should be retrieved
|
||||
from.</para>
|
||||
<enumlist>
|
||||
<enum name="audio">
|
||||
<para>Retrieve information from the audio media stream.</para>
|
||||
<note><para>If not specified, <literal>audio</literal> is used
|
||||
by default.</para></note>
|
||||
</enum>
|
||||
<enum name="video">
|
||||
<para>Retrieve information from the video media stream.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
<enum name="endpoint">
|
||||
<para>R/O The name of the endpoint associated with this channel.
|
||||
Use the <replaceable>PJSIP_ENDPOINT</replaceable> function to obtain
|
||||
further endpoint related information.</para>
|
||||
</enum>
|
||||
<enum name="contact">
|
||||
<para>R/O The name of the contact associated with this channel.
|
||||
Use the <replaceable>PJSIP_CONTACT</replaceable> function to obtain
|
||||
further contact related information. Note this may not be present and if so
|
||||
is only available on outgoing legs.</para>
|
||||
</enum>
|
||||
<enum name="aor">
|
||||
<para>R/O The name of the AOR associated with this channel.
|
||||
Use the <replaceable>PJSIP_AOR</replaceable> function to obtain
|
||||
further AOR related information. Note this may not be present and if so
|
||||
is only available on outgoing legs.</para>
|
||||
</enum>
|
||||
<enum name="pjsip">
|
||||
<para>R/O Obtain information about the current PJSIP channel and its
|
||||
session.</para>
|
||||
<parameter name="type" required="true">
|
||||
<para>When <replaceable>pjsip</replaceable> is specified, the
|
||||
<literal>type</literal> parameter must be provided. It specifies
|
||||
which signalling parameter to read.</para>
|
||||
<enumlist>
|
||||
<enum name="call-id">
|
||||
<para>The SIP call-id.</para>
|
||||
</enum>
|
||||
<enum name="secure">
|
||||
<para>Whether or not the signalling uses a secure transport.</para>
|
||||
<enumlist>
|
||||
<enum name="0"><para>The signalling uses a non-secure transport.</para></enum>
|
||||
<enum name="1"><para>The signalling uses a secure transport.</para></enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="target_uri">
|
||||
<para>The contact URI where requests are sent.</para>
|
||||
</enum>
|
||||
<enum name="local_uri">
|
||||
<para>The local URI.</para>
|
||||
</enum>
|
||||
<enum name="local_tag">
|
||||
<para>Tag in From header</para>
|
||||
</enum>
|
||||
<enum name="remote_uri">
|
||||
<para>The remote URI.</para>
|
||||
</enum>
|
||||
<enum name="remote_tag">
|
||||
<para>Tag in To header</para>
|
||||
</enum>
|
||||
<enum name="request_uri">
|
||||
<para>The request URI of the incoming <literal>INVITE</literal>
|
||||
associated with the creation of this channel.</para>
|
||||
</enum>
|
||||
<enum name="t38state">
|
||||
<para>The current state of any T.38 fax on this channel.</para>
|
||||
<enumlist>
|
||||
<enum name="DISABLED"><para>T.38 faxing is disabled on this channel.</para></enum>
|
||||
<enum name="LOCAL_REINVITE"><para>Asterisk has sent a <literal>re-INVITE</literal> to the remote end to initiate a T.38 fax.</para></enum>
|
||||
<enum name="REMOTE_REINVITE"><para>The remote end has sent a <literal>re-INVITE</literal> to Asterisk to initiate a T.38 fax.</para></enum>
|
||||
<enum name="ENABLED"><para>A T.38 fax session has been enabled.</para></enum>
|
||||
<enum name="REJECTED"><para>A T.38 fax session was attempted but was rejected.</para></enum>
|
||||
</enumlist>
|
||||
</enum>
|
||||
<enum name="local_addr">
|
||||
<para>On inbound calls, the full IP address and port number that
|
||||
the <literal>INVITE</literal> request was received on. On outbound
|
||||
calls, the full IP address and port number that the <literal>INVITE</literal>
|
||||
request was transmitted from.</para>
|
||||
</enum>
|
||||
<enum name="remote_addr">
|
||||
<para>On inbound calls, the full IP address and port number that
|
||||
the <literal>INVITE</literal> request was received from. On outbound
|
||||
calls, the full IP address and port number that the <literal>INVITE</literal>
|
||||
request was transmitted to.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</info>
|
||||
<info name="CHANNEL_EXAMPLES" language="en_US" tech="PJSIP">
|
||||
<example title="PJSIP specific CHANNEL examples">
|
||||
; Log the current Call-ID
|
||||
same => n,Log(NOTICE, ${CHANNEL(pjsip,call-id)})
|
||||
|
||||
; Log the destination address of the audio stream
|
||||
same => n,Log(NOTICE, ${CHANNEL(rtp,dest)})
|
||||
|
||||
; Store the round-trip time associated with a
|
||||
; video stream in the CDR field video-rtt
|
||||
same => n,Set(CDR(video-rtt)=${CHANNEL(rtcp,rtt,video)})
|
||||
</example>
|
||||
</info>
|
||||
</docs>
|
|
@ -148,4 +148,24 @@ int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char
|
|||
*/
|
||||
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
|
||||
|
||||
#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
|
||||
/*!
|
||||
* \brief Hang up an incoming PJSIP channel with a SIP response code
|
||||
* \param chan The channel the function is called on
|
||||
* \param data SIP response code or name
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int pjsip_app_hangup(struct ast_channel *chan, const char *data);
|
||||
|
||||
/*!
|
||||
* \brief Manager action to hang up an incoming PJSIP channel with a SIP response code
|
||||
* \param s session
|
||||
* \param m message
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int pjsip_action_hangup(struct mansession *s, const struct message *m);
|
||||
|
||||
#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
|
||||
|
|
|
@ -805,6 +805,11 @@ int analog_available(struct analog_pvt *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* If line is being held, definitely not (don't allow call waitings to an on-hook phone) */
|
||||
if (p->cshactive) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If no owner definitely available */
|
||||
if (!p->owner) {
|
||||
offhook = analog_is_off_hook(p);
|
||||
|
@ -1073,6 +1078,8 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/* Name and Number */
|
||||
n = ast_channel_connected(ast)->id.name.valid ? ast_channel_connected(ast)->id.name.str : NULL;
|
||||
l = ast_channel_connected(ast)->id.number.valid ? ast_channel_connected(ast)->id.number.str : NULL;
|
||||
if (l) {
|
||||
|
@ -1087,12 +1094,25 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, const char *rdest
|
|||
}
|
||||
|
||||
if (p->use_callerid) {
|
||||
const char *qual_var;
|
||||
|
||||
/* Caller ID Name and Number */
|
||||
p->caller.id.name.str = p->lastcid_name;
|
||||
p->caller.id.number.str = p->lastcid_num;
|
||||
p->caller.id.name.valid = ast_channel_connected(ast)->id.name.valid;
|
||||
p->caller.id.number.valid = ast_channel_connected(ast)->id.number.valid;
|
||||
p->caller.id.name.presentation = ast_channel_connected(ast)->id.name.presentation;
|
||||
p->caller.id.number.presentation = ast_channel_connected(ast)->id.number.presentation;
|
||||
|
||||
/* Redirecting Reason */
|
||||
p->redirecting_reason = ast_channel_redirecting(ast)->from.number.valid ? ast_channel_redirecting(ast)->reason.code : -1;
|
||||
|
||||
/* Call Qualifier */
|
||||
ast_channel_lock(ast);
|
||||
/* XXX In the future, we may want to make this a CALLERID or CHANNEL property and fetch it from there. */
|
||||
qual_var = pbx_builtin_getvar_helper(ast, "CALL_QUALIFIER");
|
||||
p->call_qualifier = ast_true(qual_var) ? 1 : 0;
|
||||
ast_channel_unlock(ast);
|
||||
}
|
||||
|
||||
ast_setstate(ast, AST_STATE_RINGING);
|
||||
|
@ -1285,6 +1305,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
|
|||
p->channel, idx, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
|
||||
if (idx > -1) {
|
||||
/* Real channel, do some fixup */
|
||||
p->cshactive = 0;
|
||||
p->subs[idx].owner = NULL;
|
||||
p->polarity = POLARITY_IDLE;
|
||||
analog_set_linear_mode(p, idx, 0);
|
||||
|
@ -1451,6 +1472,8 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
|
|||
ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
|
||||
p->callwaitcas = 0;
|
||||
analog_set_callwaiting(p, p->permcallwaiting);
|
||||
/* In theory, the below is not necessary since we set hidecallerid = permhidecaller when calls start,
|
||||
* but this ensures the setting is defaulted properly when channels are idle, too. */
|
||||
p->hidecallerid = p->permhidecallerid;
|
||||
analog_set_dialing(p, 0);
|
||||
analog_update_conf(p);
|
||||
|
@ -1741,10 +1764,7 @@ static void *__analog_ss_thread(void *data)
|
|||
|
||||
ast_debug(1, "%s %d\n", __FUNCTION__, p->channel);
|
||||
|
||||
if (!chan) {
|
||||
/* What happened to the channel? */
|
||||
goto quit;
|
||||
}
|
||||
ast_assert(chan != NULL);
|
||||
|
||||
if ((callid = ast_channel_callid(chan))) {
|
||||
ast_callid_threadassoc_add(callid);
|
||||
|
@ -2133,12 +2153,26 @@ static void *__analog_ss_thread(void *data)
|
|||
case ANALOG_SIG_FXOLS:
|
||||
case ANALOG_SIG_FXOGS:
|
||||
case ANALOG_SIG_FXOKS:
|
||||
/* Set our default presentation.
|
||||
* This is necessary because the presentation for each call is independent
|
||||
* (though the default may be the same).
|
||||
* For example, if hidecallerid=yes and somebody makes a call with *82,
|
||||
* then makes a 3-way call, the presentation for the 2nd call should still
|
||||
* be blocked, unless that also had a *82.
|
||||
* For this reason, setting hidecallerid = permhidecallerid on hangup
|
||||
* is NOT sufficient, as the *82 from the first call could "leak" into
|
||||
* subsequent ones made before a hangup, improperly leaking a number
|
||||
* that should have been hidden.
|
||||
*/
|
||||
p->hidecallerid = p->permhidecallerid;
|
||||
|
||||
/* Read the first digit */
|
||||
timeout = analog_get_firstdigit_timeout(p);
|
||||
/* If starting a threeway call, never timeout on the first digit so someone
|
||||
can use flash-hook as a "hold" feature */
|
||||
if (p->subs[ANALOG_SUB_THREEWAY].owner) {
|
||||
timeout = 999999;
|
||||
* can use flash-hook as a "hold" feature...
|
||||
* ...Unless three-way dial tone should time out to silence, in which case the default suffices. */
|
||||
if (!p->threewaysilenthold && p->subs[ANALOG_SUB_THREEWAY].owner) {
|
||||
timeout = INT_MAX;
|
||||
}
|
||||
while (len < AST_MAX_EXTENSION-1) {
|
||||
int is_exten_parking = 0;
|
||||
|
@ -2190,18 +2224,18 @@ static void *__analog_ss_thread(void *data)
|
|||
res = analog_play_tone(p, idx, -1);
|
||||
ast_channel_lock(chan);
|
||||
ast_channel_exten_set(chan, exten);
|
||||
if (!ast_strlen_zero(p->cid_num)) {
|
||||
if (!p->hidecallerid) {
|
||||
ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
|
||||
} else {
|
||||
ast_set_callerid(chan, NULL, NULL, p->cid_num);
|
||||
}
|
||||
}
|
||||
if (!ast_strlen_zero(p->cid_name)) {
|
||||
if (!p->hidecallerid) {
|
||||
ast_set_callerid(chan, NULL, p->cid_name, NULL);
|
||||
}
|
||||
|
||||
/* Properly set the presentation.
|
||||
* We need to do this here as well, because p->hidecallerid might be set
|
||||
* due to permanent blocking, not star-67/star-82 usage. */
|
||||
if (p->hidecallerid) {
|
||||
ast_channel_caller(chan)->id.number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
ast_channel_caller(chan)->id.name.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
} else {
|
||||
ast_channel_caller(chan)->id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
|
||||
ast_channel_caller(chan)->id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
|
||||
}
|
||||
|
||||
ast_setstate(chan, AST_STATE_RING);
|
||||
ast_channel_unlock(chan);
|
||||
analog_set_echocanceller(p, 1);
|
||||
|
@ -2219,7 +2253,11 @@ static void *__analog_ss_thread(void *data)
|
|||
}
|
||||
} else if (res == 0) {
|
||||
ast_debug(1, "not enough digits (and no ambiguous match)...\n");
|
||||
res = analog_play_tone(p, idx, ANALOG_TONE_CONGESTION);
|
||||
if (p->threewaysilenthold) {
|
||||
ast_debug(1, "Nothing dialed at three-way dial tone, timed out to silent hold\n");
|
||||
} else {
|
||||
res = analog_play_tone(p, idx, ANALOG_TONE_CONGESTION);
|
||||
}
|
||||
analog_wait_event(p);
|
||||
ast_hangup(chan);
|
||||
goto quit;
|
||||
|
@ -2263,9 +2301,11 @@ static void *__analog_ss_thread(void *data)
|
|||
ast_hangup(chan);
|
||||
goto quit;
|
||||
}
|
||||
|
||||
/* While the DMS-100 allows dialing as many *67s and *82s in succession as one's heart may desire,
|
||||
* the 5ESS does not, it only allows pure toggling (and only once!). So, it's not incorrect
|
||||
* to prevent people from dialing *67 if that won't actually do anything. */
|
||||
} else if (!p->hidecallerid && !strcmp(exten, "*67")) {
|
||||
ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
|
||||
ast_verb(3, "Blocking Caller*ID on %s\n", ast_channel_name(chan));
|
||||
/* Disable Caller*ID if enabled */
|
||||
p->hidecallerid = 1;
|
||||
ast_channel_caller(chan)->id.number.presentation = AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
|
||||
|
@ -2352,7 +2392,7 @@ static void *__analog_ss_thread(void *data)
|
|||
len = 0;
|
||||
}
|
||||
} else if (p->hidecallerid && !strcmp(exten, "*82")) {
|
||||
ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
|
||||
ast_verb(3, "Allowing Caller*ID on %s\n", ast_channel_name(chan));
|
||||
/* Enable Caller*ID if enabled */
|
||||
p->hidecallerid = 0;
|
||||
ast_channel_caller(chan)->id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
|
||||
|
@ -2713,6 +2753,7 @@ int analog_ss_thread_start(struct analog_pvt *p, struct ast_channel *chan)
|
|||
{
|
||||
pthread_t threadid;
|
||||
|
||||
p->ss_astchan = chan;
|
||||
return ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, p);
|
||||
}
|
||||
|
||||
|
@ -2775,9 +2816,13 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
|
|||
analog_set_pulsedial(p, (res & ANALOG_EVENT_PULSEDIGIT) ? 1 : 0);
|
||||
ast_debug(1, "Detected %sdigit '%c'\n", (res & ANALOG_EVENT_PULSEDIGIT) ? "pulse ": "", res & 0xff);
|
||||
analog_confmute(p, 0);
|
||||
p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
|
||||
p->subs[idx].f.subclass.integer = res & 0xff;
|
||||
analog_handle_dtmf(p, ast, idx, &f);
|
||||
if (p->dialmode == ANALOG_DIALMODE_BOTH || p->dialmode == ANALOG_DIALMODE_PULSE) {
|
||||
p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
|
||||
p->subs[idx].f.subclass.integer = res & 0xff;
|
||||
analog_handle_dtmf(p, ast, idx, &f);
|
||||
} else {
|
||||
ast_debug(1, "Dropping pulse digit '%c' because pulse dialing disabled on channel %d\n", res & 0xff, p->channel);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -2892,6 +2937,34 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
|
|||
analog_get_and_handle_alarms(p);
|
||||
cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
|
||||
case ANALOG_EVENT_ONHOOK:
|
||||
if (p->calledsubscriberheld && (p->sig == ANALOG_SIG_FXOLS || p->sig == ANALOG_SIG_FXOGS || p->sig == ANALOG_SIG_FXOKS) && idx == ANALOG_SUB_REAL) {
|
||||
ast_debug(4, "Channel state on %s is %d\n", ast_channel_name(ast), ast_channel_state(ast));
|
||||
/* Called Subscriber Held: don't let the called party hang up on an incoming call immediately (if it's the only call). */
|
||||
if (p->subs[ANALOG_SUB_CALLWAIT].owner || p->subs[ANALOG_SUB_THREEWAY].owner) {
|
||||
ast_debug(2, "Letting this call hang up normally, since it's not the only call\n");
|
||||
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || ast_channel_state(ast) != AST_STATE_UP) {
|
||||
ast_debug(2, "Called Subscriber Held does not apply: channel state is %d\n", ast_channel_state(ast));
|
||||
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || strcmp(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner), "AppDial")) {
|
||||
/* Called Subscriber held only applies to incoming calls, not outgoing calls.
|
||||
* We can't use p->outgoing because that is always true, for both incoming and outgoing calls, so it's not accurate.
|
||||
* We can check the channel application/data instead.
|
||||
* For incoming calls to the channel, it will look like: AppDial / (Outgoing Line)
|
||||
* We only want this behavior for regular calls anyways (and not, say, Queue),
|
||||
* so this would actually work great. But accessing ast_channel_appl can cause a crash if there are no calls left,
|
||||
* so this check must occur AFTER we confirm the channel state *is* still UP.
|
||||
*/
|
||||
ast_debug(2, "Called Subscriber Held does not apply: not an incoming call\n");
|
||||
} else if (analog_is_off_hook(p)) {
|
||||
ast_log(LOG_WARNING, "Got ONHOOK but channel %d is off hook?\n", p->channel); /* Shouldn't happen */
|
||||
} else {
|
||||
ast_verb(3, "Holding incoming call %s for channel %d\n", ast_channel_name(ast), p->channel);
|
||||
/* Inhibit dahdi_hangup from getting called, and do nothing else now.
|
||||
* When the DAHDI channel goes off hook again, it'll just get reconnected with the incoming call,
|
||||
* to which, as far as its concerned, nothing has happened. */
|
||||
p->cshactive = 1; /* Keep track that this DAHDI channel is currently being held by an incoming call. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
|
||||
ast_channel_hangupcause_hash_set(ast, cause_code, data_size);
|
||||
switch (p->sig) {
|
||||
|
@ -3731,6 +3804,32 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
/* Handle an event on a given channel for the monitor thread. */
|
||||
switch (event) {
|
||||
case ANALOG_EVENT_WINKFLASH:
|
||||
case ANALOG_EVENT_RINGBEGIN:
|
||||
switch (i->sig) {
|
||||
case ANALOG_SIG_FXSLS:
|
||||
case ANALOG_SIG_FXSGS:
|
||||
case ANALOG_SIG_FXSKS:
|
||||
if (i->immediate) {
|
||||
if (i->use_callerid || i->usedistinctiveringdetection) {
|
||||
ast_log(LOG_WARNING, "Can't start PBX immediately, must wait for Caller ID / distinctive ring\n");
|
||||
} else {
|
||||
/* If we don't care about Caller ID or Distinctive Ring, then there's
|
||||
* no need to wait for anything before accepting the call, as
|
||||
* waiting will buy us nothing.
|
||||
* So if the channel is configured for immediate, actually start immediately
|
||||
* and get the show on the road as soon as possible. */
|
||||
ast_debug(1, "Disabling ring timeout (previously %d) to begin handling immediately\n", i->ringt_base);
|
||||
analog_set_ringtimeout(i, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
if (!(ISTRUNK(i) && i->immediate && !i->use_callerid && !i->usedistinctiveringdetection)) {
|
||||
break;
|
||||
}
|
||||
case ANALOG_EVENT_RINGOFFHOOK:
|
||||
if (i->inalarm) {
|
||||
break;
|
||||
|
@ -3742,6 +3841,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
case ANALOG_SIG_FXOKS:
|
||||
res = analog_off_hook(i);
|
||||
i->fxsoffhookstate = 1;
|
||||
i->cshactive = 0;
|
||||
if (res && (errno == EBUSY)) {
|
||||
break;
|
||||
}
|
||||
|
@ -3753,7 +3853,10 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
if (i->immediate) {
|
||||
analog_set_echocanceller(i, 1);
|
||||
/* The channel is immediately up. Start right away */
|
||||
res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
|
||||
if (i->immediatering) {
|
||||
/* Play fake ringing, if we've been told to... */
|
||||
res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_RINGTONE);
|
||||
}
|
||||
chan = analog_new_ast_channel(i, AST_STATE_RING, 1, ANALOG_SUB_REAL, NULL);
|
||||
if (!chan) {
|
||||
ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
|
||||
|
|
|
@ -116,6 +116,13 @@ enum analog_dsp_digitmode {
|
|||
ANALOG_DIGITMODE_MF,
|
||||
};
|
||||
|
||||
enum analog_dialmode {
|
||||
ANALOG_DIALMODE_BOTH = 0,
|
||||
ANALOG_DIALMODE_PULSE,
|
||||
ANALOG_DIALMODE_DTMF,
|
||||
ANALOG_DIALMODE_NONE,
|
||||
};
|
||||
|
||||
enum analog_cid_start {
|
||||
ANALOG_CID_START_POLARITY = 1,
|
||||
ANALOG_CID_START_POLARITY_IN,
|
||||
|
@ -282,16 +289,19 @@ struct analog_pvt {
|
|||
unsigned int ani_wink_time:16; /* Safe wait time before we wink to start ANI spill */
|
||||
|
||||
unsigned int answeronpolarityswitch:1;
|
||||
unsigned int calledsubscriberheld:1; /*!< TRUE if a single incoming call can hold an FXS channel */
|
||||
unsigned int callreturn:1;
|
||||
unsigned int cancallforward:1;
|
||||
unsigned int canpark:1;
|
||||
unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
|
||||
unsigned int hanguponpolarityswitch:1;
|
||||
unsigned int immediate:1;
|
||||
unsigned int immediatering:1; /*!< TRUE if ringing should be provided for immediate execution */
|
||||
unsigned int permcallwaiting:1; /*!< TRUE if call waiting is enabled. (Configured option) */
|
||||
unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
|
||||
unsigned int pulse:1;
|
||||
unsigned int threewaycalling:1;
|
||||
unsigned int threewaysilenthold:1; /*!< Whether to time out a three-way dial tone to silence */
|
||||
unsigned int transfer:1;
|
||||
unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
|
||||
unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
|
||||
|
@ -308,6 +318,7 @@ struct analog_pvt {
|
|||
int channel; /*!< Channel Number */
|
||||
|
||||
enum analog_sigtype outsigmod;
|
||||
enum analog_dialmode dialmode; /*!< Which of pulse and/or tone dialing to support */
|
||||
int echotraining;
|
||||
int cid_signalling; /*!< Asterisk callerid type we're using */
|
||||
int polarityonanswerdelay;
|
||||
|
@ -320,6 +331,7 @@ struct analog_pvt {
|
|||
|
||||
/* XXX: All variables after this are internal */
|
||||
unsigned int callwaiting:1; /*!< TRUE if call waiting is enabled. (Active option) */
|
||||
unsigned int cshactive:1; /*!< TRUE if FXS channel is currently held by an incoming call */
|
||||
unsigned int dialednone:1;
|
||||
unsigned int dialing:1; /*!< TRUE if in the process of dialing digits or sending something */
|
||||
unsigned int dnd:1; /*!< TRUE if Do-Not-Disturb is enabled. */
|
||||
|
@ -334,12 +346,15 @@ struct analog_pvt {
|
|||
* gives a positive reply.
|
||||
*/
|
||||
unsigned int callwaitcas:1;
|
||||
unsigned int call_qualifier:1; /*!< Call qualifier delivery */
|
||||
|
||||
char callwait_num[AST_MAX_EXTENSION];
|
||||
char callwait_name[AST_MAX_EXTENSION];
|
||||
char lastcid_num[AST_MAX_EXTENSION];
|
||||
char lastcid_name[AST_MAX_EXTENSION];
|
||||
struct ast_party_caller caller;
|
||||
int redirecting_reason; /*!< Redirecting reason */
|
||||
|
||||
int cidrings; /*!< Which ring to deliver CID on */
|
||||
char echorest[20];
|
||||
int polarity;
|
||||
|
|
|
@ -597,20 +597,20 @@ static int parse_config(int reload)
|
|||
if (!strcasecmp(var->name, "quality")) {
|
||||
res = abs(atoi(var->value));
|
||||
if (res > -1 && res < 11) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting Quality to %d\n",res);
|
||||
ast_verb(5, "CODEC SPEEX: Setting Quality to %d\n",res);
|
||||
quality = res;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error Quality must be 0-10\n");
|
||||
} else if (!strcasecmp(var->name, "complexity")) {
|
||||
res = abs(atoi(var->value));
|
||||
if (res > -1 && res < 11) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting Complexity to %d\n",res);
|
||||
ast_verb(5, "CODEC SPEEX: Setting Complexity to %d\n",res);
|
||||
complexity = res;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! Complexity must be 0-10\n");
|
||||
} else if (!strcasecmp(var->name, "vbr_quality")) {
|
||||
if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0 && res_f <= 10) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
|
||||
ast_verb(5, "CODEC SPEEX: Setting VBR Quality to %f\n",res_f);
|
||||
vbr_quality = res_f;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! VBR Quality must be 0-10\n");
|
||||
|
@ -618,62 +618,62 @@ static int parse_config(int reload)
|
|||
ast_log(LOG_ERROR,"Error! ABR Quality setting obsolete, set ABR to desired bitrate\n");
|
||||
} else if (!strcasecmp(var->name, "enhancement")) {
|
||||
enhancement = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Perceptual Enhancement Mode. [%s]\n",enhancement ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "vbr")) {
|
||||
vbr = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: VBR Mode. [%s]\n",vbr ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "abr")) {
|
||||
res = abs(atoi(var->value));
|
||||
if (res >= 0) {
|
||||
if (res > 0)
|
||||
ast_verb(3, "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
|
||||
ast_verb(5, "CODEC SPEEX: Setting ABR target bitrate to %d\n",res);
|
||||
else
|
||||
ast_verb(3, "CODEC SPEEX: Disabling ABR\n");
|
||||
ast_verb(5, "CODEC SPEEX: Disabling ABR\n");
|
||||
abr = res;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! ABR target bitrate must be >= 0\n");
|
||||
} else if (!strcasecmp(var->name, "vad")) {
|
||||
vad = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: VAD Mode. [%s]\n",vad ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "dtx")) {
|
||||
dtx = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: DTX Mode. [%s]\n",dtx ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "preprocess")) {
|
||||
preproc = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Preprocessing. [%s]\n",preproc ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "pp_vad")) {
|
||||
pp_vad = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Preprocessor VAD. [%s]\n",pp_vad ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "pp_agc")) {
|
||||
pp_agc = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Preprocessor AGC. [%s]\n",pp_agc ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "pp_agc_level")) {
|
||||
if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
|
||||
ast_verb(5, "CODEC SPEEX: Setting preprocessor AGC Level to %f\n",res_f);
|
||||
pp_agc_level = res_f;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! Preprocessor AGC Level must be >= 0\n");
|
||||
} else if (!strcasecmp(var->name, "pp_denoise")) {
|
||||
pp_denoise = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Preprocessor Denoise. [%s]\n",pp_denoise ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "pp_dereverb")) {
|
||||
pp_dereverb = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Preprocessor Dereverb. [%s]\n",pp_dereverb ? "on" : "off");
|
||||
} else if (!strcasecmp(var->name, "pp_dereverb_decay")) {
|
||||
if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
|
||||
ast_verb(5, "CODEC SPEEX: Setting preprocessor Dereverb Decay to %f\n",res_f);
|
||||
pp_dereverb_decay = res_f;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Decay must be >= 0\n");
|
||||
} else if (!strcasecmp(var->name, "pp_dereverb_level")) {
|
||||
if (sscanf(var->value, "%30f", &res_f) == 1 && res_f >= 0) {
|
||||
ast_verb(3, "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
|
||||
ast_verb(5, "CODEC SPEEX: Setting preprocessor Dereverb Level to %f\n",res_f);
|
||||
pp_dereverb_level = res_f;
|
||||
} else
|
||||
ast_log(LOG_ERROR,"Error! Preprocessor Dereverb Level must be >= 0\n");
|
||||
} else if (!strcasecmp(var->name, "experimental_rtcp_feedback")) {
|
||||
exp_rtcp_fb = ast_true(var->value) ? 1 : 0;
|
||||
ast_verb(3, "CODEC SPEEX: Experimental RTCP Feedback. [%s]\n",exp_rtcp_fb ? "on" : "off");
|
||||
ast_verb(5, "CODEC SPEEX: Experimental RTCP Feedback. [%s]\n",exp_rtcp_fb ? "on" : "off");
|
||||
}
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue