Compare commits
862 Commits
Author | SHA1 | Date |
---|---|---|
Asterisk Development Team | ac87f47b32 | |
Asterisk Development Team | a4248c671a | |
Benjamin Keith Ford | a3e0fdeb46 | |
George Joseph | 8cc49544f8 | |
Ben Ford | ad66cbd0be | |
Asterisk Development Team | 987ad61270 | |
Friendly Automation | 574a7bfa97 | |
George Joseph | e6cc1f5083 | |
Kevin Harwell | a92fdd25ac | |
Asterisk Development Team | 6a68c75ac7 | |
Asterisk Development Team | e70a65eb55 | |
Friendly Automation | 1535da1b7d | |
George Joseph | 2b75c4fc51 | |
Kevin Harwell | 6b072ab08c | |
Joshua Colp | deb45228c8 | |
Guido Falsi | 8931669b37 | |
Asterisk Development Team | 951d914aab | |
Asterisk Development Team | 688908fe7a | |
Joshua Colp | cb90d1cd7c | |
George Joseph | c49696462a | |
Friendly Automation | ce5029a4db | |
sungtae kim | b478f46d59 | |
Friendly Automation | a30e2ea305 | |
Friendly Automation | 55fbf9b2c3 | |
George Joseph | d566314e38 | |
George Joseph | f4726e8b16 | |
Friendly Automation | c4cefb8073 | |
Sean Bright | bf527810ef | |
Frederic LE FOLL | c6b17b5212 | |
Frederic LE FOLL | c8cf3ad389 | |
George Joseph | 1158411f53 | |
Joshua Colp | 2691ee7e10 | |
Kevin Harwell | 965df3c228 | |
Chris-Savinovich | a321225fa4 | |
Igor Goncharovsky | 92261d60c8 | |
George Joseph | 260969f5ad | |
George Joseph | cc1b57a51d | |
George Joseph | 712bf5edee | |
Kevin Harwell | 7db5f5df6a | |
Igor Goncharovsky | 78d00c277c | |
Igor Goncharovsky | 821b7561f8 | |
Sean Bright | cdbb9800e3 | |
Friendly Automation | 94dfb9c7ac | |
Friendly Automation | d29e16ce52 | |
George Joseph | b5eb13c23b | |
George Joseph | 38d1d0726c | |
Alexei Gradinari | aaaa1695ca | |
George Joseph | c00a010fe8 | |
George Joseph | 6407ccd2d9 | |
George Joseph | 23882ddb3e | |
Dan Cropp | c8cc530726 | |
Friendly Automation | ad63cb7cef | |
Stas Kobzar | fb984eda40 | |
George Joseph | f82d0b74fd | |
Sean Bright | 51fd43206b | |
Alexei Gradinari | ff180a5bfc | |
Sean Bright | 8399211eaf | |
George Joseph | c8c33c9a0b | |
George Joseph | b0208d6e2f | |
George Joseph | 92066b8746 | |
Kevin Harwell | d4766a82a2 | |
George Joseph | db9684ad1e | |
Friendly Automation | d7c826af92 | |
Joshua Colp | 6350f4e278 | |
George Joseph | 9feb13c5b1 | |
George Joseph | 2641081caa | |
Friendly Automation | 27deec9ee2 | |
George Joseph | ef38087532 | |
Kevin Harwell | 6bb14150c4 | |
Sean Bright | 9718376902 | |
Joshua Colp | c2b135729c | |
Friendly Automation | 8de36bfa41 | |
Friendly Automation | d3508f5b51 | |
Torrey Searle | 83390327b2 | |
Sean Bright | 0ebfc4a19d | |
Sean Bright | d6af1acb8c | |
George Joseph | 05cf9c9912 | |
George Joseph | 50453846b6 | |
George Joseph | 06780d2bc4 | |
Sean Bright | 28654308ef | |
George Joseph | 85dcc699fa | |
George Joseph | d2a2131447 | |
Friendly Automation | f7c30bc93d | |
Friendly Automation | 24219c8d1d | |
George Joseph | 2b407cb531 | |
Friendly Automation | 6e33772432 | |
George Joseph | fcd0c9c325 | |
Leonid Fainshtein | 3814faf848 | |
Tzafrir Cohen | 06515707df | |
Tzafrir Cohen | 93a093f6c4 | |
Tzafrir Cohen | a45cfefb77 | |
Tzafrir Cohen | ec6e88592a | |
Tzafrir Cohen | 7b6df814a6 | |
George Joseph | 356f4256cc | |
George Joseph | 979e4119d6 | |
Dan Cropp | f4896703b9 | |
Rodrigo Ramírez Norambuena | 9d69469203 | |
Friendly Automation | f73fb5fdb1 | |
George Joseph | c86c0973ff | |
Joshua Colp | eed3336f89 | |
Friendly Automation | fcd598c310 | |
Asterisk Development Team | cb831a18d1 | |
Walter Doekes | 64d25d36fb | |
George Joseph | f62d9013c1 | |
Kevin Harwell | 88ea395c33 | |
Joshua Colp | 1756029237 | |
Friendly Automation | 0e3a3a5cb7 | |
George Joseph | 2126dc3021 | |
Francesco Castellano | 6c59df17a5 | |
Joshua Colp | 1b832c3b60 | |
Chris-Savinovich | da1db4f842 | |
Kevin Harwell | 83aba363fe | |
George Joseph | 31ef22ead1 | |
George Joseph | 205a255b27 | |
Kevin Harwell | 323b1e5fe5 | |
George Joseph | 0dc61e41fa | |
George Joseph | 2db5173b88 | |
Kevin Harwell | d2a696cc04 | |
George Joseph | 7d48e086ca | |
George Joseph | 33b3f8b09f | |
Friendly Automation | 635affeac5 | |
George Joseph | 31d755e805 | |
Friendly Automation | a464847a1b | |
Friendly Automation | 25c6890864 | |
Nasir Iqbal | 52a3d4a761 | |
George Joseph | 01712bbdc9 | |
George Joseph | 1ee2f01f62 | |
Alexei Gradinari | 8b77318a2c | |
George Joseph | ccc92b6ecb | |
Sean Bright | 694097ee68 | |
Joshua Colp | 82789aafd6 | |
George Joseph | ca462f6e15 | |
George Joseph | 5c2bf122ed | |
George Joseph | da5874ec47 | |
Joshua Colp | 5c32680bb7 | |
George Joseph | e7d0ca1591 | |
agupta | 72f26aa8eb | |
Kirsty Tyerman | a1c84709b8 | |
Chris-Savinovich | c2621aa190 | |
Alexei Gradinari | 86cd77ec0a | |
Alexei Gradinari | 6321b559b9 | |
Joshua Colp | de38c9c3b3 | |
Friendly Automation | eefd53b718 | |
Friendly Automation | c945d3d9c8 | |
Friendly Automation | 53df0ff200 | |
Asterisk Development Team | d2c07aceca | |
Friendly Automation | 7053104222 | |
Alexei Gradinari | e77704f45c | |
Alexei Gradinari | e0a574253e | |
Ben Ford | ec74fd56a7 | |
Guido Falsi | 86fb72c4d0 | |
Friendly Automation | 0fc6617246 | |
George Joseph | a99f814414 | |
Morten Tryfoss | 9351aa3f0e | |
Alexei Gradinari | db5bc0fabf | |
Alexei Gradinari | 9516fb64c9 | |
Joshua Colp | 33ed2e1bb8 | |
George Joseph | 79b15d0b30 | |
Joshua Colp | 2aa9bc6d2c | |
Friendly Automation | 2de4f668be | |
Friendly Automation | a1a8c47f53 | |
Friendly Automation | 790b9223ed | |
Alexei Gradinari | de82bdd746 | |
Joshua Colp | cf2f8db1b7 | |
George Joseph | e7734476c6 | |
Joshua Colp | ece29db9bd | |
Ben Ford | 941dead08d | |
Kevin Harwell | edc3e0df1a | |
agupta | 9a0fa51443 | |
George Joseph | 543d487746 | |
Joshua Colp | 8357ab7e9a | |
Friendly Automation | 27696cbda6 | |
Friendly Automation | 748f1d64a1 | |
Friendly Automation | 7bddfdbfa6 | |
George Joseph | 5002169d6a | |
agupta | 39c5188bec | |
Holger Hans Peter Freyther | f599ebd29e | |
Joshua Colp | d861ebdca8 | |
Joshua Colp | 5023f02b2d | |
Friendly Automation | f2cb892d7c | |
Friendly Automation | a6863e5beb | |
Friendly Automation | 60d13c3d56 | |
agupta | 1d214a3623 | |
Ben Ford | 8d35a30a3f | |
Antoni Goldstein | d6b37e2926 | |
Kevin Harwell | e3a758975d | |
Friendly Automation | 92712891f9 | |
Friendly Automation | 641414faf9 | |
George Joseph | e281911667 | |
Guido Falsi | 4dcfa8d127 | |
Lucas Mendes | daed593cfa | |
Friendly Automation | 6ec4b113c1 | |
Friendly Automation | 74d79bdf71 | |
Friendly Automation | 93d36953fb | |
George Joseph | 7487fc88d2 | |
Friendly Automation | bc45d0497c | |
Dan Cropp | eca8c440d2 | |
Friendly Automation | c9ca88ae7d | |
Friendly Automation | ff7b0acc4e | |
Sean Bright | 022e784b7a | |
Benjamin Keith Ford | 873280c708 | |
Joshua Colp | 7a6895baf5 | |
Joshua Colp | d734e1bbfa | |
Joshua Colp | 95dac45148 | |
George Joseph | 18fe583d12 | |
Sean Bright | d0a8334e4f | |
George Joseph | 03b6d18e99 | |
George Joseph | 62cf7eae92 | |
George Joseph | a53f54856d | |
Sean Bright | 9b7a64cbf0 | |
Friendly Automation | 49b751d153 | |
Sean Bright | 34b9b65098 | |
George Joseph | 898765d919 | |
Sean Bright | 116dc9c9b3 | |
Sean Bright | ea3109beaa | |
Sean Bright | 71c7864d1d | |
Friendly Automation | fbed32a1a5 | |
Sean Bright | f91262272e | |
Alexander Anikin | eec16b8e99 | |
George Joseph | b414cf09ac | |
Alexei Gradinari | acfbfef8ad | |
Joshua Colp | 0dde010f13 | |
Ben Ford | ef404fef91 | |
George Joseph | 0fb456d2ae | |
George Joseph | 1988cf795c | |
Friendly Automation | 777ee8290a | |
Friendly Automation | 90781674ad | |
Chris-Savinovich | 85bbb7a3e8 | |
Salah Ahmed | 7e5b4b8616 | |
sungtae kim | d5a318f148 | |
Sebastian Kemper | 8ec4de7501 | |
Joshua Colp | 4f0b8c3ed3 | |
Friendly Automation | b394eed481 | |
George Joseph | 1464a6b80f | |
Ben Ford | 8961d9ca8b | |
Kevin Harwell | 94eeba6147 | |
George Joseph | 5f21b5f3df | |
Matthew Fredrickson | ae1aeb930e | |
Sean Bright | 6f5a6072ab | |
Ben Ford | 64279e5992 | |
George Joseph | bc06a13123 | |
sungtae kim | 5815597a21 | |
Friendly Automation | eebc98fa44 | |
sungtae kim | bbc13b1f1f | |
George Joseph | 0bcbf97cb7 | |
Friendly Automation | 5592ae465e | |
Ben Ford | 636e301f91 | |
Sean Bright | d4cd2a9706 | |
Friendly Automation | e1b0961fce | |
Sean Bright | 3e5b26ae0a | |
Friendly Automation | 03c5b916ff | |
George Joseph | 4ec943fdee | |
Joshua Colp | 4d8cd2efbe | |
Alexei Gradinari | e51bd0726b | |
sungtae kim | 6d455487d9 | |
Sean Bright | d905602a04 | |
Alexei Gradinari | 634314c727 | |
Matthew Fredrickson | ce5bed44e4 | |
Friendly Automation | c7d29cdcf2 | |
George Joseph | 396dac8888 | |
George Joseph | 7bdde83f2c | |
Friendly Automation | f151f72870 | |
Joshua Colp | 67db353598 | |
George Joseph | aba1053a12 | |
sungtae kim | 9e36707dca | |
Sean Bright | 057c7380be | |
Richard Mudgett | 0426e0fede | |
Joshua C. Colp | 6f10c9cf4f | |
George Joseph | f5f977baec | |
Joshua C. Colp | de3f28ec8a | |
Joshua C. Colp | 3e5dcc9dcf | |
cirillor | 342550e0ea | |
Joshua C. Colp | d3c971c315 | |
Kevin Harwell | 19957fc60e | |
Kevin Harwell | 0e053fe4e3 | |
Joshua Colp | 03c0d19cc8 | |
Joshua C. Colp | c8a1f8bfaa | |
Kevin Harwell | 6a435723f7 | |
George Joseph | a71ae3dc44 | |
Chris-Savinovich | 47c853f8e1 | |
Friendly Automation | b428363cd5 | |
George Joseph | 9b15e04011 | |
Joshua Colp | b886fef66e | |
Friendly Automation | 13cca7bb11 | |
sungtae kim | ca8f254f0f | |
cirillor | c9459b1875 | |
Sean Bright | 8ca74d73f1 | |
Torrey Searle | 4ca41caf38 | |
Corey Farrell | 641b6041c7 | |
George Joseph | 255e374254 | |
Friendly Automation | 70cd169fb1 | |
Friendly Automation | afe16021ef | |
Friendly Automation | 7566d9bb61 | |
Sean Bright | 5b5aa05bd9 | |
Sean Bright | 4860954540 | |
Sean Bright | 90f06ad169 | |
Ben Ford | 50a4b618fc | |
Dömsödi Gergely | e7dd4bd4a9 | |
Joshua Colp | 24b94aa27f | |
Joshua Colp | 293df3c7ac | |
Joshua Colp | f9bc474ab0 | |
Joshua Colp | 7bdbccc64a | |
Sean Bright | 88681ba9bb | |
Sean Bright | 0cfafb89b5 | |
Joshua Colp | 90f0f6659d | |
Joshua Colp | 6a714c0e9f | |
sungtae kim | 0d7012044a | |
Rodrigo Ramírez Norambuena | 63a3321c46 | |
Sean Bright | ffe07772e6 | |
Friendly Automation | 2a387f04db | |
Kevin Harwell | 436975dd6e | |
Joshua Colp | a08ee6c962 | |
Sean Bright | 625af27a28 | |
George Joseph | 61585af9bd | |
Joshua Colp | 1d7df1d3f1 | |
Sean Bright | 6f1c0e787c | |
Joshua Colp | ae1b12b834 | |
Joshua Colp | c268b3592c | |
Sean Bright | fe694de299 | |
Sean Bright | edf31624a2 | |
Kevin Harwell | b3ebb51086 | |
George Joseph | 6e8cba39a4 | |
Joshua C. Colp | cc8aa4eee1 | |
George Joseph | 8402189892 | |
Torrey Searle | 5b8db4e422 | |
Joshua C. Colp | aefc501913 | |
Joshua C. Colp | 8b3579a7e5 | |
Joshua C. Colp | b5426cb111 | |
Friendly Automation | db5ff02982 | |
Joshua C. Colp | 4378c4ee72 | |
Kevin Harwell | cab8a76ae3 | |
Joshua C. Colp | 9905cccb7b | |
Joshua C. Colp | a2254c5878 | |
Joshua Colp | 0896e4cdc6 | |
Friendly Automation | bd992f686d | |
Friendly Automation | 2846b54ee2 | |
Sungtae Kim | a1391aa26b | |
George Joseph | bb8903b00e | |
Joshua C. Colp | 4b6c60b362 | |
George Joseph | 2f8def1453 | |
Kevin Harwell | 1c5def4b18 | |
Friendly Automation | 4a871c4b79 | |
Friendly Automation | 3ae7dada41 | |
George Joseph | c0e2a93e42 | |
Rodrigo Ramírez Norambuena | e806990be2 | |
sungtae kim | 08ba504e99 | |
Sungtae Kim | 3fe40c0c05 | |
Joshua Colp | 3a2db0ee04 | |
Kevin Harwell | e85f92f37a | |
Torrey Searle | 01b781b4dc | |
Chris Savinovich | b327b0bbda | |
George Joseph | aaee80adfe | |
Joshua C. Colp | 2070f62bb6 | |
Joshua Colp | 1084b6e1a1 | |
Kevin Harwell | 2cf3931379 | |
Joshua Colp | 44254d548b | |
George Joseph | c0b7b60ba1 | |
George Joseph | 7e366e4d4b | |
Sungtae Kim | e3e3027092 | |
Giuseppe Sucameli | 419db481d1 | |
George Joseph | 3d54ef5978 | |
George Joseph | 29a77b337d | |
George Joseph | c925742e8b | |
sungtae kim | 19fc99a2fb | |
Sean Bright | f29da72969 | |
Joshua C. Colp | ffe6ecb40f | |
Ben Ford | 1051e1dd18 | |
Joshua C. Colp | 6ccf1155d1 | |
George Joseph | 70fa6e6955 | |
Kevin Harwell | 9c3b4dcf80 | |
George Joseph | 603143bd5a | |
George Joseph | 36a10a3672 | |
George Joseph | d0087a8107 | |
George Joseph | 47a2b6d0f3 | |
Kevin Harwell | f6452f9656 | |
Joshua C. Colp | e994dff064 | |
eyalhasson | c1da2e94a3 | |
Joshua C. Colp | fe4c6434c1 | |
Joshua C. Colp | e2fb30245b | |
Joshua C. Colp | a40fb7fa7f | |
Jean Aunis | d3a6714158 | |
Joshua C. Colp | 6640ecfd39 | |
Jeremy Lainé | 907d71b551 | |
Joshua C. Colp | 7d1736b59b | |
Joshua C. Colp | 84bed54bd7 | |
Joshua C. Colp | fc28aa2de6 | |
Xiemin Chen | f6cf837aed | |
Joshua C. Colp | ef43bd0b43 | |
Gerald Schnabel | 735bd4d185 | |
Chris-Savinovich | 05b79d16ab | |
George Joseph | dbef559e0b | |
Kevin Harwell | f1fb249132 | |
George Joseph | 9c11399be3 | |
Sean Bright | fb6e0df173 | |
Valentin Vidic | 6506c5b1d4 | |
Joshua C. Colp | fcd07c34fb | |
Sean Bright | 011e46d5a6 | |
Jeremy Lainé | 21a1feece2 | |
Sean Bright | 44a862fb57 | |
Joshua C. Colp | 9e7e150a13 | |
Friendly Automation | d76896a30b | |
Joshua C. Colp | 11d63c9e4f | |
Joshua C. Colp | 32934180f9 | |
Joshua C. Colp | 72fdba63a8 | |
mohitdhiman | 4b24da607e | |
Diederik de Groot | d2c182b6ab | |
Alexei Gradinari | 7f22c9f4b7 | |
Joshua Colp | c6271155fb | |
Alexei Gradinari | c0e57e458b | |
Joshua C. Colp | 701cd2ee58 | |
Friendly Automation | 140ed330ac | |
Joshua C. Colp | 1e9da4dba6 | |
Joshua C. Colp | 92ee1bdfbb | |
Bryan Boatright | 92298434bd | |
Joshua Colp | 2d9482695d | |
Richard Mudgett | f196078705 | |
George Joseph | 4ff64bfc2c | |
Corey Farrell | 44a7faca21 | |
George Joseph | ff2ed4eeee | |
George Joseph | 3efe5061d5 | |
Richard Mudgett | 59717b5e85 | |
Joshua C. Colp | 08e6cb6480 | |
Friendly Automation | 0110532bf9 | |
George Joseph | 4cbe04de77 | |
George Joseph | 955129e9a4 | |
George Joseph | aebb822d1f | |
Friendly Automation | 9b57199a7a | |
Sean Bright | 970805180e | |
Joshua C. Colp | 9e159914dc | |
Sean Bright | f60afac587 | |
Joshua C. Colp | 84d693a689 | |
Joshua C. Colp | b924594104 | |
Sean Bright | 640aac768b | |
Friendly Automation | 67e91d012b | |
Joshua C. Colp | 36db878adc | |
Alexei Gradinari | 2610379605 | |
Joshua C. Colp | 68ec7d93e8 | |
Friendly Automation | ff147bcf92 | |
Joshua C. Colp | 569e556656 | |
Joshua C. Colp | 88af756419 | |
George Joseph | 66820f19c2 | |
Sean Bright | 9febdba05b | |
Sean Bright | 16ae8330d2 | |
George Joseph | cd8101dbd1 | |
Joshua C. Colp | 3336a348cc | |
Sean Bright | 9c9519796b | |
George Joseph | df0b59564e | |
Sebastian Damm | 59cf552dd3 | |
Joshua C. Colp | 29af7f37ac | |
Sean Bright | 8a18fb81c1 | |
George Joseph | 79899db740 | |
Giuseppe Sucameli | 6071ad77f5 | |
David M. Lee | 1657508ddd | |
George Joseph | a6c2662404 | |
George Joseph | 36bf94c3a8 | |
Kevin Harwell | 12a30c71d8 | |
Sean Bright | 27806fd04d | |
George Joseph | b5d3ddeef3 | |
George Joseph | 8071697653 | |
Chris-Savinovich | 1f09c61804 | |
Chris-Savinovich | 60e548ffa5 | |
Pirmin Walthert | 5de36abd5a | |
George Joseph | a2a8a41db3 | |
Kevin Harwell | 618f081c3c | |
Jenkins2 | e67537dd98 | |
lvl | aa004295f9 | |
George Joseph | a5e77e9c37 | |
George Joseph | 0ad0e89ba3 | |
Joshua Colp | 450ca98220 | |
Joshua Colp | 53d0664781 | |
Corey Farrell | 606304eb54 | |
Alexei Gradinari | 331c906c48 | |
Corey Farrell | ed7a5664b6 | |
Corey Farrell | 0d2b39065f | |
Sungtae Kim | 1b6df87816 | |
Joshua Colp | 0e096aefac | |
Jenkins2 | 5f9a17bcdb | |
Kevin Harwell | 72e532136c | |
George Joseph | 729967e99c | |
Joshua C. Colp | d05c219aad | |
Joshua Colp | 3506f84a37 | |
Joshua Colp | 2d4146d005 | |
Joshua Colp | d388977efb | |
Joshua Colp | 7f813cdec8 | |
Joshua Colp | cc0157d0d3 | |
Corey Farrell | f9b9bdd0b0 | |
George Joseph | 41eab5b3b8 | |
Sungtae Kim | cb83350230 | |
George Joseph | e0a4df64cd | |
Alexei Gradinari | e6005f1227 | |
George Joseph | 2ca3813c52 | |
Joshua Colp | 8d436a95e7 | |
George Joseph | dd0a3c0bba | |
George Joseph | 9bb155d95e | |
George Joseph | 7d11718a80 | |
George Joseph | 77e9c877b5 | |
George Joseph | 0552bc2a94 | |
George Joseph | 0ba1993887 | |
George Joseph | ccf38b3e34 | |
George Joseph | 7ba8f32632 | |
Corey Farrell | 699dfa9401 | |
Corey Farrell | 3bdf6ac918 | |
Corey Farrell | 2a76489eba | |
George Joseph | 6e1471c0b2 | |
Torrey Searle | 7b2282c890 | |
Corey Farrell | a36cd6960c | |
George Joseph | 009d67cd28 | |
Joshua Colp | bd5dde4e83 | |
George Joseph | 0785af921d | |
Corey Farrell | 89d97da8a4 | |
George Joseph | ff7a772395 | |
Robert Cripps | df703c1853 | |
Corey Farrell | 05c79fdf06 | |
Joshua Colp | 38e609656a | |
Corey Farrell | 3cde7e30ba | |
Corey Farrell | 1c008c6de5 | |
Kevin Harwell | b969e7769d | |
Corey Farrell | 07a59b783e | |
Chris-Savinovich | 9c9bc5acca | |
Joshua Colp | 907ea79a92 | |
Kevin Harwell | 03efafbd4d | |
Alexei Gradinari | 3e3f3bfb07 | |
George Joseph | 5710cf7c94 | |
Joshua Colp | 27897a850d | |
Jasper Hafkenscheid | 7f6ac5dc2f | |
Pascal Cadotte Michaud | a6d1723727 | |
George Joseph | f9708adcc8 | |
George Joseph | 021a425011 | |
George Joseph | 66a5d96c51 | |
George Joseph | b5245b6f36 | |
Joshua Colp | 9c5e75acb0 | |
Richard Mudgett | 719daf3299 | |
Alexei Gradinari | 5cbe77cc46 | |
George Joseph | e8eb659afa | |
Alexei Gradinari | fbee505611 | |
Pascal Cadotte Michaud | 6c2f9b730e | |
Torrey Searle | 3ba66b8a9d | |
Joshua Colp | 3f4f31fed6 | |
Joshua Colp | d69a0cee03 | |
Joshua Colp | b0b03c8295 | |
Richard Mudgett | fbb577577c | |
Alexei Gradinari | 190b3d7412 | |
Richard Mudgett | 11427a9665 | |
George Joseph | fec66b8f01 | |
George Joseph | 4eef448acc | |
George Joseph | 891a270275 | |
George Joseph | 7e6a7dcdc0 | |
Richard Mudgett | 1413200c7c | |
Corey Farrell | dee1165d31 | |
Corey Farrell | 90887af808 | |
Jenkins2 | 14d1e6ca2a | |
George Joseph | a3116842ff | |
George Joseph | 6989915ab6 | |
Richard Mudgett | 00284352b3 | |
Sean Bright | 495a1e7e5c | |
Richard Mudgett | 2384d6eb87 | |
Richard Mudgett | 718ccd51a3 | |
Richard Mudgett | 7687630074 | |
George Joseph | 7c7cdab2af | |
Corey Farrell | abee4fd072 | |
George Joseph | ebd8e0720d | |
Richard Mudgett | 3fe9c41342 | |
George Joseph | 8c2c6ba913 | |
Corey Farrell | 35f44be460 | |
Alexei Gradinari | 0f53930c05 | |
George Joseph | 649ee402e5 | |
George Joseph | a529aa9bfe | |
Corey Farrell | 08e5bbfec0 | |
Corey Farrell | a5023d4f75 | |
Kevin Harwell | 31fed39078 | |
Corey Farrell | 5ea517f80e | |
Richard Mudgett | c001974f4f | |
George Joseph | b42c682213 | |
George Joseph | f636d6d187 | |
George Joseph | 04fcfe856a | |
George Joseph | 0e38d72b35 | |
George Joseph | 7b0ecf7274 | |
George Joseph | 46d8d8959c | |
neutrino88 | e0496fe062 | |
Corey Farrell | c6ee3cf639 | |
Richard Mudgett | 77f151d927 | |
Richard Mudgett | bc335ceda8 | |
George Joseph | 6fd21a6af6 | |
George Joseph | 1598c7a306 | |
Jenkins2 | f9cc33c821 | |
George Joseph | 1debf9e484 | |
George Joseph | 24f44474b6 | |
George Joseph | 48bac78f3e | |
George Joseph | be88c768f4 | |
George Joseph | 99e05591fa | |
Sean Bright | b2f96fdcfe | |
Sean Bright | d0a1237c19 | |
Corey Farrell | 48bb4543d9 | |
George Joseph | d027d193b8 | |
George Joseph | 26123b01cb | |
George Joseph | 161ad96c3e | |
Richard Mudgett | 7eda6263c2 | |
Richard Mudgett | 5b72bb0278 | |
Corey Farrell | fa9cd68589 | |
George Joseph | aae29f38ea | |
George Joseph | dae4c4c95d | |
George Joseph | e7b1de5150 | |
George Joseph | 0e93826e64 | |
Sean Bright | 8b3b504b79 | |
Sean Bright | 5f7350d68b | |
Sean Bright | 2b4752911f | |
Corey Farrell | 3b2310332d | |
Richard Mudgett | c2e6efa63d | |
Corey Farrell | 326574d4fc | |
Corey Farrell | 65f06a4505 | |
Corey Farrell | f066dbc353 | |
neutrino88 | 406c5bef0a | |
Joshua Colp | b351b903b9 | |
Joshua Colp | c69e5cd764 | |
Corey Farrell | 693e00eee6 | |
Corey Farrell | 5a9230eacb | |
Richard Mudgett | a2554d5e5a | |
Jenkins2 | 42b1e197c8 | |
Jenkins2 | 68fe182e4f | |
George Joseph | 8c72cd8459 | |
Joshua Colp | 339e248524 | |
Joshua Colp | 81fca7f7ac | |
Joshua Colp | ddbd902edf | |
Joshua Colp | c87945c25d | |
Corey Farrell | 266ed3d68b | |
Alexei Gradinari | ab90479642 | |
Corey Farrell | 3337fe85c5 | |
Corey Farrell | b3b95c8d36 | |
George Joseph | 0ad987168e | |
Kevin Harwell | 2ee1c0cec8 | |
George Joseph | 60754fb806 | |
George Joseph | 15f91a4789 | |
George Joseph | b4ab26e72f | |
George Joseph | de43d25716 | |
Corey Farrell | 33455f8d6f | |
Sean Bright | d1698b4e0b | |
George Joseph | 06fef54b5a | |
Joshua Colp | 2e307ee0b7 | |
Corey Farrell | 0fe08c5e79 | |
Cao Minh Hiep | 958727cece | |
Moritz Fain | 1f68614f3c | |
Ben Ford | 67e1e49e08 | |
George Joseph | 94ef074cc7 | |
George Joseph | 7638366c2f | |
Alexei Gradinari | e04c49b517 | |
George Joseph | 227d9719da | |
George Joseph | a6c3984175 | |
pk16208 | 681e115ff1 | |
George Joseph | cc8e0dfabd | |
Joshua Colp | 7c49ea7cff | |
Corey Farrell | ede59966d9 | |
Corey Farrell | 7b0dbda936 | |
George Joseph | 3ddfeccf35 | |
George Joseph | 685abce1d0 | |
George Joseph | 6a0dc87b97 | |
George Joseph | 82f28106df | |
George Joseph | 64e3ed75ab | |
George Joseph | a389b020de | |
George Joseph | 361295f192 | |
Kevin Harwell | 755febe497 | |
George Joseph | ba91c73f8e | |
George Joseph | 0a1a96d331 | |
Corey Farrell | 7a7b21f3a0 | |
Sean Bright | 880905e7eb | |
George Joseph | fa1b836374 | |
George Joseph | dec6ebd9e1 | |
Sean Bright | 339bf0cf7b | |
George Joseph | 1a9c69d729 | |
Joshua Colp | 84b60aeb70 | |
hajekd | 8811ab1803 | |
Joshua Colp | 36898351e5 | |
Joshua Colp | 2f38bcdfc0 | |
Joshua Colp | e313ec3a7e | |
Joshua Colp | 3c1a8be11e | |
Richard Mudgett | f6695249a5 | |
Richard Mudgett | c008c27c85 | |
Joshua Colp | 7912ad9bf7 | |
George Joseph | 40082f3e00 | |
Richard Mudgett | 192f71b7de | |
Joshua Colp | 60258b4ec1 | |
Florian Floimair | 3e48c34f14 | |
George Joseph | 29115e2384 | |
Joshua Colp | 6e79e6b097 | |
Sean Bright | b0a0b975c5 | |
George Joseph | 0107e1aa5a | |
Jenkins2 | 4300410c9a | |
George Joseph | 4a309839eb | |
Sean Bright | 55ca51af21 | |
Sean Bright | 887a315e17 | |
George Joseph | 3f9544c1f5 | |
George Joseph | 349355f1f1 | |
George Joseph | 17d6d9e1e7 | |
George Joseph | 06d51a0408 | |
George Joseph | 9db82309d5 | |
Jenkins2 | 39829f0a78 | |
Corey Farrell | 5842741689 | |
Walter Doekes | 78453e65fd | |
Joshua Colp | 7ed02b4925 | |
lvl | f4bffe2326 | |
Sean Bright | e5739c494c | |
Corey Farrell | ecb3b23b07 | |
Frederic LE FOLL | ccfd2e0f5d | |
Jenkins2 | c1a2c84361 | |
Joshua Colp | 3c52cc32f1 | |
Joshua Colp | 6344cceed2 | |
Joshua Colp | af6a3d02e1 | |
lvl | 034a3d8b86 | |
Sean Bright | 3134fd95a9 | |
George Joseph | ead0bc63da | |
George Joseph | 9fb166cf3b | |
George Joseph | 85a7c33acf | |
George Joseph | 597f612645 | |
George Joseph | 10460501ca | |
Rodrigo Ramírez Norambuena | 8879a62c1c | |
Chris-Savinovich | cfb854e241 | |
Joshua Colp | ed7cef7d06 | |
Richard Mudgett | 4fcdcfaa37 | |
Richard Mudgett | f6a165208b | |
Joshua Colp | 62afa54977 | |
Joshua Colp | ad37ab9a8f | |
Richard Mudgett | 4dd8b5bbb4 | |
Rodrigo Ramírez Norambuena | 1edd9eb309 | |
Joshua Colp | 6f27ad59f5 | |
Joshua Colp | 390d0b42ca | |
George Joseph | a52b56b4d1 | |
Sean Bright | 245fb462d6 | |
Corey Farrell | 1b1f47bef6 | |
neutrino88 | aa2755cbb3 | |
Joshua Colp | 3d495f89bc | |
Jenkins2 | 14c84efbfe | |
Jenkins2 | 777d125516 | |
Jaco Kroon | 46442aa9e5 | |
Jaco Kroon | d84de695ed | |
Matthew Fredrickson | 4188e7d6dd | |
Florian Floimair | 595e358761 | |
Joshua Colp | bd650b6a49 | |
Joshua Colp | 378964f403 | |
Sean Bright | 4b88cb383d | |
Joshua Colp | 6b527d11ae | |
Joshua Colp | b0db0df7b8 | |
Joshua Colp | 2454c1d310 | |
Joshua Colp | b880b50922 | |
Richard Mudgett | fb2f242c49 | |
George Joseph | 5645dc6894 | |
George Joseph | b523aaf699 | |
George Joseph | 0fe2eadbc3 | |
Joshua Colp | b9cd4c6d92 | |
Richard Mudgett | 236826a111 | |
Richard Mudgett | 19298141cf | |
Kirsty Tyerman | f6c1d94d91 | |
Richard Mudgett | 4e43823d19 | |
Richard Mudgett | 857926d197 | |
Richard Mudgett | 111e73678e | |
Richard Mudgett | a7ace944ae | |
Richard Mudgett | 0874d5b316 | |
Joshua Colp | 7d8e2389d6 | |
Joshua Colp | 14da6be84d | |
Kevin Harwell | 80a331d96b | |
George Joseph | df78227e4a | |
George Joseph | 4ca959c72c | |
George Joseph | 33a5b8ccaf | |
George Joseph | 4f95992d36 | |
Torrey Searle | 0d4bde84d1 | |
Corey Farrell | 167efe3a47 | |
Corey Farrell | 72dbc9fb70 | |
Corey Farrell | 6e0f4a2127 | |
Corey Farrell | b370482786 | |
George Joseph | 100ffc6866 | |
Jenkins2 | c03ab4c4b1 | |
George Joseph | aee6d12f15 | |
Corey Farrell | d61a8791b5 | |
Richard Mudgett | 0e4f5f5189 | |
Joshua Colp | 56c1285b8a | |
Corey Farrell | 3bf968470b | |
Ben Ford | a46fcaca7b | |
Ivan Poddubny | fce68efbbe | |
Corey Farrell | 661273a078 | |
Kevin Harwell | 1d1473d408 | |
Joshua Colp | 4202fbdc51 | |
Joshua Colp | 0df8ab0adc | |
Joshua Colp | f568428111 | |
Joshua Colp | ef029a3224 | |
Richard Mudgett | eb87a98a1a | |
Joshua Colp | 5030756bfa | |
Joshua Colp | fcece326ed | |
Joshua Colp | baae4a5e48 | |
Alexander Traud | 04974a0ca2 | |
Richard Mudgett | 99a0586ec1 | |
Salah Ahmed | 523b7b2ffc | |
Kevin Harwell | ec813a3fdb | |
Kevin Harwell | fb862c4066 | |
Kevin Harwell | 07c23cea37 | |
Alexander Traud | e9d41572b3 | |
Joshua Colp | 1e837e13f5 | |
Joshua Colp | 19494d9481 | |
Joshua Colp | 4462990ce7 | |
Torrey Searle | e818925a58 | |
Joshua Colp | 927f68bb9d | |
Joshua Colp | 8a8569cb81 | |
Richard Mudgett | 20b53b5cee | |
George Joseph | 914b9e1934 | |
Alexander Traud | 93d1c34efe | |
Joshua Colp | ee9794d741 | |
Alexander Traud | c10b3ccd5f | |
Richard Mudgett | 32ce8e5cf3 | |
Joshua Colp | 59f53514ce | |
Alexander Traud | 8da81a208f | |
Joshua Colp | a31e877502 | |
Joshua Colp | f5dbcf122f | |
Joshua Colp | 3ce7f3a441 | |
Joshua Colp | e449bc32de | |
George Joseph | e097dca4d7 | |
Corey Farrell | e5de8a70f8 | |
neutrino88 | d3809d61cb | |
George Joseph | 798f049e82 | |
Corey Farrell | 7578881b3d | |
Kevin Harwell | 8ea13d62cd | |
Joshua Colp | e5c0ac6a64 | |
George Joseph | 4a51f2792e | |
Joshua Colp | 84b5245476 | |
Jenkins2 | 166aa49664 | |
Jenkins2 | 6e2ce299c3 | |
George Joseph | 93997f9698 | |
George Joseph | 0baf660bde | |
Corey Farrell | 74cbeabb97 | |
Corey Farrell | adf3c569a2 | |
George Joseph | e4b0f09bcc | |
Corey Farrell | 5537048d60 | |
Jenkins2 | 18a074e540 | |
George Joseph | cecff1f7ab | |
Corey Farrell | 9f3620a578 | |
George Joseph | 835489f76d | |
Florian Floimair | 1f46e2e91c | |
Jenkins2 | b9630a9591 | |
Jenkins2 | 9913a4fcca | |
George Joseph | 393428be7b | |
George Joseph | 8550fad21a | |
George Joseph | f2580d037f | |
Richard Mudgett | 35d06e46ae | |
Jenkins2 | fb6af6dbd2 | |
George Joseph | 03b1078117 | |
Corey Farrell | 09b258fd69 | |
George Joseph | 648541fe89 | |
George Joseph | ebbc29f9f5 | |
Jenkins2 | bd879a6c28 | |
Jenkins2 | 549aa07265 | |
George Joseph | 460ef41f7a | |
Jenkins2 | 4f1953da7e | |
Corey Farrell | fd1f74af40 | |
Corey Farrell | 9b3267641f | |
Joshua Colp | 0f999a834f | |
Richard Mudgett | aea0a0294d | |
Kevin Harwell | a459b560c5 | |
Corey Farrell | d2dace81d4 | |
Corey Farrell | c8bd8f6ce9 | |
George Joseph | 0f82db82cb | |
Joshua Colp | a2a3ad2438 | |
Richard Mudgett | dbffcdc561 | |
Richard Mudgett | 709b795cb0 | |
Corey Farrell | c40412bd13 | |
George Joseph | 0353c34c61 | |
Joshua Colp | 0b3bc4852f |
|
@ -1,5 +1,5 @@
|
|||
[gerrit]
|
||||
defaultbranch=master
|
||||
defaultbranch=16
|
||||
#
|
||||
# Intentional padding to ensure it is possible to point a commit
|
||||
# to an alternative gerrit server/repository without breaking
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
40
|
288
CHANGES
288
CHANGES
|
@ -1,5 +1,9 @@
|
|||
==============================================================================
|
||||
===
|
||||
=== THIS FILE IS AUTOMATICALLY GENERATED DURING THE RELEASE
|
||||
=== PROCESS. DO NOT MAKE CHANGES HERE. INSTEAD, REFER TO
|
||||
=== doc/CHANGES-staging/README.md FOR MORE DETAILS.
|
||||
===
|
||||
=== This file documents the new and/or enhanced functionality added in
|
||||
=== the Asterisk versions listed below. This file does NOT include
|
||||
=== changes in behavior that would not be backwards compatible with
|
||||
|
@ -8,6 +12,265 @@
|
|||
===
|
||||
==============================================================================
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.5.0 to Asterisk 16.6.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
ARI Channels
|
||||
------------------
|
||||
* The Channel resource has a new sub-resource "externalMedia".
|
||||
This allows an application to create a channel for the sole purpose
|
||||
of exchanging media with an external server. Once created, this
|
||||
channel could be placed into a bridge with existing channels to
|
||||
allow the external server to inject audio into the bridge or
|
||||
receive audio from the bridge.
|
||||
See https://wiki.asterisk.org/wiki/display/AST/External+Media+and+ARI
|
||||
for more information.
|
||||
|
||||
Build
|
||||
------------------
|
||||
* Two new Makefile targets have been added... "install-headers" and
|
||||
"uninstall-headers" to separately control header installation.
|
||||
The existing behavior has not changed so "make install" and
|
||||
"make uninstall" will continue to also install/uninstall the headers.
|
||||
The new targets were added for forward compatibility with Asterisk 17
|
||||
in which the headers are no longer installed/uninstalled with the
|
||||
"install" and "uninstall" targets.
|
||||
|
||||
app_mixmonitor
|
||||
------------------
|
||||
* An option 'S' has been added to MixMonitor. If used in combination with
|
||||
the r() and/or t() options, if a frame is available to write to one of
|
||||
those files but not the other, a frame of silence if written to the file
|
||||
that does not have an audio frame. This should prevent the two files
|
||||
from "drifting" when mixed after the fact.
|
||||
|
||||
chan_rtp
|
||||
------------------
|
||||
* The UnicastRTP channel driver provided by chan_rtp now accepts
|
||||
"<hostname>:<port>" as an alternative to "<ip_address>:<port>" in the destination.
|
||||
The first AAAA (preferred) or A record resolved will be used as the destination.
|
||||
The lookup is synchronous so beware of possible dialplan delays if you specify a
|
||||
hostname.
|
||||
|
||||
res_musiconhold
|
||||
------------------
|
||||
* This fix allows a realtime moh class to be unregistered from the command
|
||||
line. This is useful when the contents of a directory referenced by a
|
||||
realtime moh class have changed.
|
||||
The realtime moh class is then reloaded on the next request and uses the
|
||||
new directory contents.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.4.0 to Asterisk 16.5.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
AttendedTransfer
|
||||
------------------
|
||||
* A new application, this will queue up attended transfer to the given extension.
|
||||
|
||||
BlindTransfer
|
||||
------------------
|
||||
* A new application, this will redirect all channels currently
|
||||
bridged to the caller channel to the specified destination.
|
||||
|
||||
ReadExten
|
||||
------------------
|
||||
* Add 'p' option to stop reading extension if user presses '#' key.
|
||||
|
||||
pbx_dundi
|
||||
------------------
|
||||
* The DUNDi PBX module now supports IPv4/IPv6 dual binding.
|
||||
|
||||
res_rtp_asterisk
|
||||
------------------
|
||||
* DTLS packets will now be fragmented according to the MTU as set in rtp.conf. This
|
||||
allows larger certificates to be used for the DTLS negotiation. By default this value
|
||||
is 1200.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.3.0 to Asterisk 16.4.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
ConfBridge
|
||||
------------------
|
||||
* Add "average_all", "highest_all", and "lowest_all" values for
|
||||
the remb_behavior option. These values operate on a bridge
|
||||
level instead of a per-source level. This means that a single
|
||||
REMB value is calculated and sent to every sender, instead of
|
||||
a REMB value that is unique for the specific sender..
|
||||
|
||||
Dial
|
||||
------------------
|
||||
* Add RINGTIME and RINGTIME_MS variables containing respectively seconds and
|
||||
milliseconds between creation of the dialing channel and receiving the first
|
||||
RINGING signal
|
||||
|
||||
Add PROGRESSTIME and PROGRESSTIME_MS variables analogous to the above with respect to
|
||||
the PROGRESS signal. Shorter of these two times should be equivalent to
|
||||
the PDD (Post Dial Delay) value
|
||||
|
||||
Add DIALEDTIME_MS and ANSWEREDTIME_MS variables to get millisecond resolution
|
||||
versions of DIALEDTIME and ANSWEREDTIME
|
||||
|
||||
RTP/ICE
|
||||
------------------
|
||||
* You can now indicate that you'd like an ice_host_candidate's local address
|
||||
to be published as well as the mapped address. See the sample rtp.conf
|
||||
for more information.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Added a new PJSIP global setting called norefersub.
|
||||
Default is true to keep support working as before.
|
||||
|
||||
res_pjsip_refer configures PJSIP norefersub capability accordingly.
|
||||
|
||||
Checks the PJSIP global setting value.
|
||||
If it is true (default) it adds the norefersub capability to PJSIP.
|
||||
If it is false (disabled) it does not add the norefersub capability
|
||||
to PJSIP.
|
||||
|
||||
This is useful for Cisco switches that do not follow RFC4488.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.2.0 to Asterisk 16.3.0 ----------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
ARI
|
||||
------------------
|
||||
* Application event filtering is now supported. An application can now specify
|
||||
an "allowed" and/or "disallowed" list(s) of event types. Only those types
|
||||
indicated in the "allowed" list are sent to the application. Conversely, any
|
||||
types defined in the "disallowed" list are not sent to the application. Note
|
||||
that if a type is specified in both lists "disallowed" takes precedence.
|
||||
|
||||
* A new REST API call has been added: 'move'. It follows the format
|
||||
'channels/{channelId}/move' and can be used to move channels from one application
|
||||
to another without needing to exit back into the dialplan. An application must be
|
||||
specified, but the passing a list of arguments to the new application is optional.
|
||||
An example call would look like this:
|
||||
|
||||
client.channels.move(channelId=chan.id, app='ari-example', appArgs='a,b,c')
|
||||
|
||||
If the channel was inside of a bridge when switching applications, it will
|
||||
remain there. If the application specified cannot be moved to, then the channel
|
||||
will remain in the current application and an event will be triggered named
|
||||
"ApplicationMoveFailed", which will provide the destination application's name
|
||||
and the channel information.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* A new configuration parameter "taskprocessor_overload_trigger" has been
|
||||
added to the pjsip.conf "globals" section. The distributor currently stops
|
||||
accepting new requests when any taskprocessor overload is triggered. The
|
||||
new option allows you to completely disable overload detection (NOT
|
||||
RECOMMENDED), keep the current behavior, or trigger only on pjsip
|
||||
taskprocessor overloads.
|
||||
|
||||
chan_pjsip
|
||||
------------------
|
||||
* A new configuration parameter 'ignore_183_without_sdp' has been added
|
||||
to the pjsip.conf "endpoints" section. If enabled, will make chan_pjsip
|
||||
discard 183s that do not contain an SDP body, which can resolve no
|
||||
ringback tone issues as well as making the behavior match chan_sip.
|
||||
|
||||
MWI
|
||||
------------------
|
||||
* A new module "res_mwi_devstate" has been added that allows subscriptions
|
||||
to voicemail boxes using "presence" events. This allows common BLF keys
|
||||
to act as voicemail waiting indicators.
|
||||
|
||||
app_queue
|
||||
------------------
|
||||
* Added the ability to set the wrapuptime per-member using the AddQueueMember
|
||||
application.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.1.0 to Asterisk 16.2.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
ARI
|
||||
------------------
|
||||
* Whenever an ARI application is started, a context will be created for it
|
||||
automatically as long as one does not already exist, following the format
|
||||
'stasis-<app_name>'. Two extensions are also added to this context: a match-all
|
||||
extension, and the 'h' extension. Any phone that registers under this context
|
||||
will place all calls to the corresponding Stasis application.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Added "send_contact_status_on_update_registration" global configuration option
|
||||
to enable sending AMI ContactStatus event when a device refreshes its registration.
|
||||
|
||||
Core
|
||||
------------------
|
||||
* Reworked the media indexer so it doesn't cache the index. Testing revealed
|
||||
that the cache added no benefit but that it could consume excessive memory.
|
||||
Two new index related functions were created: ast_sounds_get_index_for_file()
|
||||
and ast_media_index_update_for_file() which restrict index updating to
|
||||
specific sound files. The original ast_sounds_get_index() and
|
||||
ast_media_index_update() calls are still available but since they no longer
|
||||
cache the results internally, developers should re-use an index they may
|
||||
already have instead of calling ast_sounds_get_index() repeatedly. If
|
||||
information for only a single file is needed, ast_sounds_get_index_for_file()
|
||||
should be called instead of ast_sounds_get_index().
|
||||
|
||||
Features
|
||||
------------------
|
||||
* Before Asterisk 12, when using the automon or automixmon features defined
|
||||
in features.conf, a channel variable (TOUCH_MIXMONITOR_OUTPUT) was set on
|
||||
both channels, indicating the filename of the recording.
|
||||
|
||||
When bridging was overhauled in Asterisk 12, the behavior was changed such
|
||||
that the variable was only set on the peer channel and not on the channel
|
||||
that initiated the automon or automixmon.
|
||||
|
||||
The previous behavior has been restored so both channels receive the
|
||||
channel variable when one of these features is invoked.
|
||||
|
||||
app_voicemail
|
||||
------------------
|
||||
* You can now specify a special context with the "aliasescontext" parameter
|
||||
in voicemail.conf which will allow you to create aliases for physical
|
||||
mailboxes.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
pbx_config
|
||||
------------------
|
||||
* pbx_config will now find and process multiple 'globals' sections from
|
||||
extensions.conf. Variables are processed in the order they are found
|
||||
and duplicate variables overwrite the previous value.
|
||||
|
||||
chan_pjsip
|
||||
------------------
|
||||
* New dialplan function PJSIP_PARSE_URI added to parse an URI and return
|
||||
a specified part of the URI.
|
||||
|
||||
Core
|
||||
------------------
|
||||
* ast_bt_get_symbols() now returns a vector of strings instead of an
|
||||
array of strings. This must be freed with ast_bt_free_symbols.
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* New options 'trust_connected_line' and 'send_connected_line' have been
|
||||
added to the endpoint. The option 'trust_connected_line' is to control
|
||||
if connected line updates are accepted from this endpoint.
|
||||
The option 'send_connected_line' is to control if connected line updates
|
||||
can be sent to this endpoint.
|
||||
The default value is 'yes' for both options.
|
||||
|
||||
res_rtp_asterisk
|
||||
------------------
|
||||
* The existing strictrtp option in rtp.conf has a new choice availabe, called
|
||||
'seqno', which behaves the same way as setting strictrtp to 'yes', but will
|
||||
ignore the time interval during learning so that bursts of packets can still
|
||||
trigger learning our source.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 15 to Asterisk 16 --------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -31,6 +294,9 @@ Build System
|
|||
MALLOC_DEBUG and vice versa. Third-party pre-compiled modules no longer
|
||||
need to have a special build with it enabled.
|
||||
|
||||
* Asterisk now depends on libjansson >= 2.11. If this version is not
|
||||
available on your distro you can use `./configure --with-jansson-bundled`.
|
||||
|
||||
app_macro
|
||||
------------------
|
||||
* The app_macro module is now deprecated and by default it is no longer
|
||||
|
@ -61,6 +327,10 @@ AMI
|
|||
and ContactStatusDetail are now set to "NonQualified" when a contact exists
|
||||
but has not been qualified.
|
||||
|
||||
* The "Newexten" event is now part of the "dialplan" class. The documentation
|
||||
for Asterisk 15 already specified this, but the implementation was actually
|
||||
using the "call" class instead.
|
||||
|
||||
ARI
|
||||
------------------
|
||||
* The ContactInfo event's contact_status field is now set to "NonQualified"
|
||||
|
@ -122,12 +392,23 @@ format_jpeg
|
|||
------------------
|
||||
* The format_jpeg module has been removed.
|
||||
|
||||
pbx_dundi
|
||||
------------------
|
||||
* DUNDi now supports IPv6
|
||||
|
||||
Core:
|
||||
------------------
|
||||
* libedit is no longer available as an embedded library and must be provided
|
||||
by the system.
|
||||
* The STATIC_BUILD functionality has been removed as it has not been maintained
|
||||
and has not worked in quite some time.
|
||||
* The module loader now enforces inter-module dependencies. This ensures that
|
||||
a module is not started before another it depends on, even if preload is used.
|
||||
If a dependency is not available or fails to startup this will block any
|
||||
dependants from startup.
|
||||
* Parts of the Asterisk core which can load configuration from realtime are now
|
||||
built-in modules. It is no longer necessary to preload realtime drivers as
|
||||
they are always initialized before the built-in modules.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 15.5.0 to Asterisk 15.6.0 ------------
|
||||
|
@ -140,6 +421,13 @@ res_pjsip
|
|||
when both 'SIP' and 'Q.850' Reason headers are received. This option allows
|
||||
the 'Q.850' Reason header to be suppressed. The default value is 'no'.
|
||||
|
||||
res_pjsip_endpoint_identifier_ip
|
||||
------------------
|
||||
* Added regex support to the identify section match_header option. You
|
||||
specify a regex instead of an explicit string by surrounding the header
|
||||
value with slashes:
|
||||
match_header = SIPHeader: /regex/
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 15.4.0 to Asterisk 15.5.0 ------------
|
||||
------------------------------------------------------------------------------
|
||||
|
|
49
Makefile
49
Makefile
|
@ -555,7 +555,6 @@ INSTALLDIRS="$(ASTLIBDIR)" "$(ASTMODDIR)" "$(ASTSBINDIR)" "$(ASTETCDIR)" "$(ASTV
|
|||
"$(ASTSPOOLDIR)" "$(ASTSPOOLDIR)/dictate" "$(ASTSPOOLDIR)/meetme" \
|
||||
"$(ASTSPOOLDIR)/monitor" "$(ASTSPOOLDIR)/system" "$(ASTSPOOLDIR)/tmp" \
|
||||
"$(ASTSPOOLDIR)/voicemail" "$(ASTSPOOLDIR)/recording" \
|
||||
"$(ASTHEADERDIR)" "$(ASTHEADERDIR)/doxygen" \
|
||||
"$(ASTLOGDIR)" "$(ASTLOGDIR)/cdr-csv" "$(ASTLOGDIR)/cdr-custom" \
|
||||
"$(ASTLOGDIR)/cel-custom" "$(ASTDATADIR)" "$(ASTDATADIR)/documentation" \
|
||||
"$(ASTDATADIR)/documentation/thirdparty" "$(ASTDATADIR)/firmware" \
|
||||
|
@ -574,19 +573,13 @@ installdirs:
|
|||
main-bininstall:
|
||||
+@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" ASTLIBDIR="$(ASTLIBDIR)" $(SUBMAKE) -C main bininstall
|
||||
|
||||
bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall
|
||||
bininstall: _all installdirs $(SUBDIRS_INSTALL) main-bininstall install-headers
|
||||
$(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
|
||||
$(INSTALL) -m 644 include/asterisk.h "$(DESTDIR)$(includedir)"
|
||||
$(INSTALL) -m 644 include/asterisk/*.h "$(DESTDIR)$(ASTHEADERDIR)"
|
||||
$(INSTALL) -m 644 include/asterisk/doxygen/*.h "$(DESTDIR)$(ASTHEADERDIR)/doxygen"
|
||||
if [ -n "$(OLDHEADERS)" ]; then \
|
||||
for h in $(OLDHEADERS); do rm -f "$(DESTDIR)$(ASTHEADERDIR)/$$h"; done \
|
||||
fi
|
||||
|
||||
ifneq ($(DISABLE_XMLDOC),yes)
|
||||
$(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation"
|
||||
|
@ -763,7 +756,7 @@ upgrade: bininstall
|
|||
# (1) the configuration directory to install from
|
||||
# (2) the extension to strip off
|
||||
define INSTALL_CONFIGS
|
||||
@for x in configs/$(1)/*$(2); do \
|
||||
@for x in $(1)/*$(2); do \
|
||||
dst="$(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x $(2)`"; \
|
||||
if [ -f "$${dst}" ]; then \
|
||||
if [ "$(OVERWRITE)" = "y" ]; then \
|
||||
|
@ -799,6 +792,24 @@ define INSTALL_CONFIGS
|
|||
fi
|
||||
endef
|
||||
|
||||
install-headers:
|
||||
# Will create all components of "$(DESTDIR)$(ASTHEADERDIR)/doxygen" including "$(DESTDIR)$(includedir)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTHEADERDIR)/doxygen"
|
||||
$(INSTALL) -m 644 include/asterisk.h "$(DESTDIR)$(includedir)"
|
||||
$(INSTALL) -m 644 include/asterisk/*.h "$(DESTDIR)$(ASTHEADERDIR)"
|
||||
$(INSTALL) -m 644 include/asterisk/doxygen/*.h "$(DESTDIR)$(ASTHEADERDIR)/doxygen"
|
||||
if [ -n "$(OLDHEADERS)" ]; then \
|
||||
for h in $(OLDHEADERS); do rm -f "$(DESTDIR)$(ASTHEADERDIR)/$$h"; done \
|
||||
fi
|
||||
|
||||
install-configs:
|
||||
@if test -z "$(CONFIG_SRC)" -o ! -d "$(CONFIG_SRC)"; then \
|
||||
>&2 echo "CONFIG_SRC must be set to a directory."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Installing config files from $(CONFIG_SRC)/*$(CONFIG_EXTEN)"
|
||||
$(call INSTALL_CONFIGS,$(CONFIG_SRC),$(CONFIG_EXTEN))
|
||||
|
||||
# XXX why *.adsi is installed first ?
|
||||
adsi:
|
||||
@echo Installing adsi config files...
|
||||
|
@ -815,7 +826,7 @@ adsi:
|
|||
|
||||
samples: adsi
|
||||
@echo Installing other config files...
|
||||
$(call INSTALL_CONFIGS,samples,.sample)
|
||||
$(call INSTALL_CONFIGS,configs/samples,.sample)
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/INBOX"
|
||||
build_tools/make_sample_voicemail "$(DESTDIR)/$(ASTDATADIR)" "$(DESTDIR)/$(ASTSPOOLDIR)"
|
||||
@for x in phoneprov/*; do \
|
||||
|
@ -838,7 +849,7 @@ samples: adsi
|
|||
|
||||
basic-pbx:
|
||||
@echo Installing basic-pbx config files...
|
||||
$(call INSTALL_CONFIGS,basic-pbx)
|
||||
$(call INSTALL_CONFIGS,configs/basic-pbx)
|
||||
|
||||
webvmail:
|
||||
@[ -d "$(DESTDIR)$(HTTP_DOCSDIR)/" ] || ( printf "http docs directory not found.\nUpdate assignment of variable HTTP_DOCSDIR in Makefile!\n" && exit 1 )
|
||||
|
@ -938,7 +949,7 @@ config:
|
|||
if [ -z "$(DESTDIR)" ] ; then \
|
||||
/sbin/chkconfig --add asterisk ; \
|
||||
fi ; \
|
||||
elif [ -f /etc/os-release ] && [ "opensuse" = "$(shell . /etc/os-release && echo $$ID)" ] ; then \
|
||||
elif [ -f /etc/os-release ] && [ "opensuse" = "$(shell . /etc/os-release 2>/dev/null && echo $$ID)" ] ; then \
|
||||
./build_tools/install_subst contrib/init.d/rc.suse.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \
|
||||
if [ ! -f /etc/sysconfig/asterisk ] ; then \
|
||||
$(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \
|
||||
|
@ -950,7 +961,7 @@ config:
|
|||
./build_tools/install_subst contrib/init.d/rc.archlinux.asterisk "$(DESTDIR)/etc/init.d/asterisk"; \
|
||||
elif [ -f /etc/slackware-version ]; then \
|
||||
./build_tools/install_subst contrib/init.d/rc.slackware.asterisk "$(DESTDIR)/etc/rc.d/rc.asterisk"; \
|
||||
elif [ -f /etc/os-release ] && [ "slackware" = "$(shell . /etc/os-release && echo $$ID)" ] ; then \
|
||||
elif [ -f /etc/os-release ] && [ "slackware" = "$(shell . /etc/os-release 2>/dev/null && echo $$ID)" ] ; then \
|
||||
./build_tools/install_subst contrib/init.d/rc.slackware.asterisk "$(DESTDIR)/etc/rc.d/rc.asterisk"; \
|
||||
elif [ -d "$(DESTDIR)/Library/LaunchDaemons" ]; then \
|
||||
if [ ! -f "$(DESTDIR)/Library/LaunchDaemons/org.asterisk.asterisk.plist" ]; then \
|
||||
|
@ -980,12 +991,15 @@ $(SUBDIRS_UNINSTALL):
|
|||
main-binuninstall:
|
||||
+@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" ASTLIBDIR="$(ASTLIBDIR)" $(SUBMAKE) -C main binuninstall
|
||||
|
||||
_uninstall: $(SUBDIRS_UNINSTALL) main-binuninstall
|
||||
uninstall-headers:
|
||||
rm -rf "$(DESTDIR)$(ASTHEADERDIR)"
|
||||
rm -f "$(DESTDIR)$(includedir)/asterisk.h"
|
||||
|
||||
_uninstall: $(SUBDIRS_UNINSTALL) main-binuninstall uninstall-headers
|
||||
rm -f "$(DESTDIR)$(ASTMODDIR)/"*
|
||||
test -n "$(_oldmoddir)" -a -d "$(_oldmoddir)" && rm -f "$(_oldmoddir)/"* || :
|
||||
rm -f "$(DESTDIR)$(ASTSBINDIR)/astgenkey"
|
||||
rm -f "$(DESTDIR)$(ASTSBINDIR)/autosupport"
|
||||
rm -rf "$(DESTDIR)$(ASTHEADERDIR)"
|
||||
rm -rf "$(DESTDIR)$(ASTDATADIR)/firmware"
|
||||
rm -f "$(DESTDIR)$(ASTMANDIR)/man8/asterisk.8"
|
||||
rm -f "$(DESTDIR)$(ASTMANDIR)/man8/astgenkey.8"
|
||||
|
@ -1015,7 +1029,7 @@ uninstall: _uninstall
|
|||
@echo " + $(mK) uninstall-all +"
|
||||
@echo " +-------------------------------------------+"
|
||||
|
||||
uninstall-all: _uninstall
|
||||
uninstall-all: _uninstall uninstall-headers
|
||||
rm -rf "$(DESTDIR)$(ASTMODDIR)"
|
||||
test -n "$(_oldmoddir)" -a -d "$(_oldmoddir)" && rm -rf "$(_oldmoddir)" || :
|
||||
rm -rf "$(DESTDIR)$(ASTVARLIBDIR)"
|
||||
|
@ -1108,6 +1122,8 @@ check-alembic: makeopts
|
|||
@find contrib/ast-db-manage/ -name '*.pyc' -delete
|
||||
@ALEMBIC=$(ALEMBIC) build_tools/make_check_alembic config cdr voicemail >&2
|
||||
|
||||
.PHONY: install-configs
|
||||
.PHONY: install-headers
|
||||
.PHONY: menuselect
|
||||
.PHONY: main
|
||||
.PHONY: sounds
|
||||
|
@ -1121,6 +1137,7 @@ check-alembic: makeopts
|
|||
.PHONY: uninstall
|
||||
.PHONY: _uninstall
|
||||
.PHONY: uninstall-all
|
||||
.PHONY: uninstall-headers
|
||||
.PHONY: badshell
|
||||
.PHONY: installdirs
|
||||
.PHONY: validate-docs
|
||||
|
|
|
@ -114,7 +114,7 @@ ifneq ($(findstring :,$(XMLSTARLET)$(BASH)),:)
|
|||
EXTERNAL_MODS=$$($(XMLSTARLET) sel -t -m "/category/member[support_level = 'external']" -v "@name" -n .moduleinfo) ;\
|
||||
for x in $${EXTERNAL_MODS} ; do \
|
||||
if [ -z "$${DISABLED_MODS[$${x}]}" ] ; then \
|
||||
$(ASTTOPDIR)/build_tools/download_externals $${x} ;\
|
||||
PJPROJECT_BUNDLED=${PJPROJECT_BUNDLED} $(ASTTOPDIR)/build_tools/download_externals $${x} ;\
|
||||
fi ;\
|
||||
done ;\
|
||||
fi
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
# Helpful functions
|
||||
# call with $(call function,...)
|
||||
tolower = $(shell echo $(1) | tr '[:upper:]' '[:lower:]')
|
||||
# Takes a list of MENUSELECT_CFLAG Id and returns CFLAGS to declare
|
||||
# the ones which are enabled.
|
||||
get_menuselect_cflags=$(patsubst %,-D%,$(filter $1,$(MENUSELECT_CFLAGS)))
|
||||
|
||||
.PHONY: dist-clean
|
||||
|
||||
|
@ -67,6 +70,17 @@ ifneq ($(findstring darwin,$(OSARCH)),)
|
|||
endif
|
||||
endif
|
||||
|
||||
# gcc version 8.2.1 and above must have partial-inlining disabled to avoid documented bug.
|
||||
# We must handle cross-compiling and clang so make sure the compiler version string has "gcc"
|
||||
# somewhere in it before testing the version.
|
||||
CC_VERS_STRING=$(shell $(CC) --version | grep -i gcc)
|
||||
ifneq ($(CC_VERS_STRING),)
|
||||
GCC_VER_GTE821:=$(shell expr `echo '$(CC_VERS_STRING)' | cut -d ' ' -f 3 | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 80201)
|
||||
ifeq ($(GCC_VER_GTE821),1)
|
||||
OPTIMIZE+=-fno-partial-inlining
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS))$(AST_CODE_COVERAGE),no)
|
||||
_ASTCFLAGS+=$(OPTIMIZE)
|
||||
else
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# The Asterisk(R) Open Source PBX
|
||||
```text
|
||||
By Mark Spencer <markster@digium.com> and the Asterisk.org developer community.
|
||||
Copyright (C) 2001-2016 Digium, Inc. and other copyright holders.
|
||||
Copyright (C) 2001-2019 Digium, Inc. and other copyright holders.
|
||||
```
|
||||
## SECURITY
|
||||
|
||||
|
|
218
UPGRADE-1.2.txt
218
UPGRADE-1.2.txt
|
@ -1,218 +0,0 @@
|
|||
=========================================================
|
||||
===
|
||||
=== Information for upgrading from Asterisk 1.0 to 1.2
|
||||
===
|
||||
=== This file documents all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also includes advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=========================================================
|
||||
|
||||
Compiling:
|
||||
|
||||
* The Asterisk 1.2 source code now uses C language features
|
||||
supported only by 'modern' C compilers. Generally, this means GCC
|
||||
version 3.0 or higher, although some GCC 2.96 releases will also
|
||||
work. Some non-GCC compilers that support C99 and the common GCC
|
||||
extensions (including anonymous structures and unions) will also
|
||||
work. All releases of GCC 2.95 do _not_ have the requisite feature
|
||||
support; systems using that compiler will need to be upgraded to
|
||||
a more recent compiler release.
|
||||
|
||||
Dialplan Expressions:
|
||||
|
||||
* The dialplan expression parser (which handles $[ ... ] constructs)
|
||||
has gone through a major upgrade, but has one incompatible change:
|
||||
spaces are no longer required around expression operators, including
|
||||
string comparisons. However, you can now use quoting to keep strings
|
||||
together for comparison. For more details, please read the
|
||||
doc/README.variables file, and check over your dialplan for possible
|
||||
problems.
|
||||
|
||||
Agents:
|
||||
|
||||
* The default for ackcall has been changed to "no" instead of "yes"
|
||||
because of a bug which caused the "yes" behavior to generally act like
|
||||
"no". You may need to adjust the value if your agents behave
|
||||
differently than you expect with respect to acknowledgement.
|
||||
|
||||
* The AgentCallBackLogin application now requires a second '|' before
|
||||
specifying an extension@context. This is to distinguish the options
|
||||
string from the extension, so that they do not conflict. See
|
||||
'show application AgentCallbackLogin' for more details.
|
||||
|
||||
Parking:
|
||||
|
||||
* Parking behavior has changed slightly; when a parked call times out,
|
||||
Asterisk will attempt to deliver the call back to the extension that
|
||||
parked it, rather than the 's' extension. If that extension is busy
|
||||
or unavailable, the parked call will be lost.
|
||||
|
||||
Dialing:
|
||||
|
||||
* The Caller*ID of the outbound leg is now the extension that was
|
||||
called, rather than the Caller*ID of the inbound leg of the call. The
|
||||
"o" flag for Dial can be used to restore the original behavior if
|
||||
desired. Note that if you are looking for the originating callerid
|
||||
from the manager event, there is a new manager event "Dial" which
|
||||
provides the source and destination channels and callerid.
|
||||
|
||||
IAX:
|
||||
|
||||
* The naming convention for IAX channels has changed in two ways:
|
||||
1. The call number follows a "-" rather than a "/" character.
|
||||
2. The name of the channel has been simplified to IAX2/peer-callno,
|
||||
rather than IAX2/peer@peer-callno or even IAX2/peer@peer/callno.
|
||||
|
||||
SIP:
|
||||
|
||||
* The global option "port" in 1.0.X that is used to set which port to
|
||||
bind to has been changed to "bindport" to be more consistent with
|
||||
the other channel drivers and to avoid confusion with the "port"
|
||||
option for users/peers.
|
||||
|
||||
* The "Registry" event now uses "Username" rather than "User" for
|
||||
consistency with IAX.
|
||||
|
||||
Applications:
|
||||
|
||||
* With the addition of dialplan functions (which operate similarly
|
||||
to variables), the SetVar application has been renamed to Set.
|
||||
|
||||
* The CallerPres application has been removed. Use SetCallerPres
|
||||
instead. It accepts both numeric and symbolic names.
|
||||
|
||||
* The applications GetGroupCount, GetGroupMatchCount, SetGroup, and
|
||||
CheckGroup have been deprecated in favor of functions. Here is a
|
||||
table of their replacements:
|
||||
|
||||
GetGroupCount([groupname][@category] GROUP_COUNT([groupname][@category]) Set(GROUPCOUNT=${GROUP_COUNT()})
|
||||
GroupMatchCount(groupmatch[@category]) GROUP_MATCH_COUNT(groupmatch[@category]) Set(GROUPCOUNT=${GROUP_MATCH_COUNT(SIP/.*)})
|
||||
SetGroup(groupname[@category]) GROUP([category])=groupname Set(GROUP()=test)
|
||||
CheckGroup(max[@category]) N/A GotoIf($[ ${GROUP_COUNT()} > 5 ]?103)
|
||||
|
||||
Note that CheckGroup does not have a direct replacement. There is
|
||||
also a new function called GROUP_LIST() which will return a space
|
||||
separated list of all of the groups set on a channel. The GROUP()
|
||||
function can also return the name of the group set on a channel when
|
||||
used in a read environment.
|
||||
|
||||
* The applications DBGet and DBPut have been deprecated in favor of
|
||||
functions. Here is a table of their replacements:
|
||||
|
||||
DBGet(foo=family/key) Set(foo=${DB(family/key)})
|
||||
DBPut(family/key=${foo}) Set(DB(family/key)=${foo})
|
||||
|
||||
* The application SetLanguage has been deprecated in favor of the
|
||||
function LANGUAGE().
|
||||
|
||||
SetLanguage(fr) Set(LANGUAGE()=fr)
|
||||
|
||||
The LANGUAGE function can also return the currently set language:
|
||||
|
||||
Set(MYLANG=${LANGUAGE()})
|
||||
|
||||
* The applications AbsoluteTimeout, DigitTimeout, and ResponseTimeout
|
||||
have been deprecated in favor of the function TIMEOUT(timeouttype):
|
||||
|
||||
AbsoluteTimeout(300) Set(TIMEOUT(absolute)=300)
|
||||
DigitTimeout(15) Set(TIMEOUT(digit)=15)
|
||||
ResponseTimeout(15) Set(TIMEOUT(response)=15)
|
||||
|
||||
The TIMEOUT() function can also return the currently set timeouts:
|
||||
|
||||
Set(DTIMEOUT=${TIMEOUT(digit)})
|
||||
|
||||
* The applications SetCIDName, SetCIDNum, and SetRDNIS have been
|
||||
deprecated in favor of the CALLERID(datatype) function:
|
||||
|
||||
SetCIDName(Joe Cool) Set(CALLERID(name)=Joe Cool)
|
||||
SetCIDNum(2025551212) Set(CALLERID(number)=2025551212)
|
||||
SetRDNIS(2024561414) Set(CALLERID(RDNIS)=2024561414)
|
||||
|
||||
* The application Record now uses the period to separate the filename
|
||||
from the format, rather than the colon.
|
||||
|
||||
* The application VoiceMail now supports a 'temporary' greeting for each
|
||||
mailbox. This greeting can be recorded by using option 4 in the
|
||||
'mailbox options' menu, and 'change your password' option has been
|
||||
moved to option 5.
|
||||
|
||||
* The application VoiceMailMain now only matches the 'default' context if
|
||||
none is specified in the arguments. (This was the previously
|
||||
documented behavior, however, we didn't follow that behavior.) The old
|
||||
behavior can be restored by setting searchcontexts=yes in voicemail.conf.
|
||||
|
||||
Queues:
|
||||
|
||||
* A queue is now considered empty not only if there are no members but if
|
||||
none of the members are available (e.g. agents not logged on). To
|
||||
restore the original behavior, use "leavewhenempty=strict" or
|
||||
"joinwhenempty=strict" instead of "=yes" for those options.
|
||||
|
||||
* It is now possible to use multi-digit extensions in the exit context
|
||||
for a queue (although you should not have overlapping extensions,
|
||||
as there is no digit timeout). This means that the EXITWITHKEY event
|
||||
in queue_log can now contain a key field with more than a single
|
||||
character in it.
|
||||
|
||||
Extensions:
|
||||
|
||||
* By default, there is a new option called "autofallthrough" in
|
||||
extensions.conf that is set to yes. Asterisk 1.0 (and earlier)
|
||||
behavior was to wait for an extension to be dialed after there were no
|
||||
more extensions to execute. "autofallthrough" changes this behavior
|
||||
so that the call will immediately be terminated with BUSY,
|
||||
CONGESTION, or HANGUP based on Asterisk's best guess. If you are
|
||||
writing an extension for IVR, you must use the WaitExten application
|
||||
if "autofallthrough" is set to yes.
|
||||
|
||||
AGI:
|
||||
|
||||
* AGI scripts did not always get SIGHUP at the end, previously. That
|
||||
behavior has been fixed. If you do not want your script to terminate
|
||||
at the end of AGI being called (e.g. on a hangup) then set SIGHUP to
|
||||
be ignored within your application.
|
||||
|
||||
* CallerID is reported with agi_callerid and agi_calleridname instead
|
||||
of a single parameter holding both.
|
||||
|
||||
Music On Hold:
|
||||
|
||||
* The preferred format for musiconhold.conf has changed; please see the
|
||||
sample configuration file for the new format. The existing format
|
||||
is still supported but will generate warnings when the module is loaded.
|
||||
|
||||
chan_modem:
|
||||
|
||||
* All the chan_modem channel drivers (aopen, bestdata and i4l) are deprecated
|
||||
in this release, and will be removed in the next major Asterisk release.
|
||||
Please migrate to chan_misdn for ISDN interfaces; there is no upgrade
|
||||
path for aopen and bestdata modem users.
|
||||
|
||||
MeetMe:
|
||||
|
||||
* The conference application now allows users to increase/decrease their
|
||||
speaking volume and listening volume (independently of each other and
|
||||
other users); the 'admin' and 'user' menus have changed, and new sound
|
||||
files are included with this release. However, if a user calling in
|
||||
over a Zaptel channel that does NOT have hardware DTMF detection
|
||||
increases their speaking volume, it is likely they will no longer be
|
||||
able to enter/exit the menu or make any further adjustments, as the
|
||||
software DTMF detector will not be able to recognize the DTMF coming
|
||||
from their device.
|
||||
|
||||
GetVar Manager Action:
|
||||
|
||||
* Previously, the behavior of the GetVar manager action reported the value
|
||||
of a variable in the following manner:
|
||||
> name: value
|
||||
This has been changed to a manner similar to the SetVar action and is now
|
||||
> Variable: name
|
||||
> Value: value
|
497
UPGRADE-1.4.txt
497
UPGRADE-1.4.txt
|
@ -1,497 +0,0 @@
|
|||
=========================================================
|
||||
===
|
||||
=== Information for upgrading from Asterisk 1.2 to 1.4
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also includes advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
===
|
||||
=========================================================
|
||||
|
||||
Build Process (configure script):
|
||||
|
||||
Asterisk now uses an autoconf-generated configuration script to learn how it
|
||||
should build itself for your system. As it is a standard script, running:
|
||||
|
||||
$ ./configure --help
|
||||
|
||||
will show you all the options available. This script can be used to tell the
|
||||
build process what libraries you have on your system (if it cannot find them
|
||||
automatically), which libraries you wish to have ignored even though they may
|
||||
be present, etc.
|
||||
|
||||
You must run the configure script before Asterisk will build, although it will
|
||||
attempt to automatically run it for you with no options specified; for most
|
||||
users, that will result in a similar build to what they would have had before
|
||||
the configure script was added to the build process (except for having to run
|
||||
'make' again after the configure script is run). Note that the configure script
|
||||
does NOT need to be re-run just to rebuild Asterisk; you only need to re-run it
|
||||
when your system configuration changes or you wish to build Asterisk with
|
||||
different options.
|
||||
|
||||
Build Process (module selection):
|
||||
|
||||
The Asterisk source tree now includes a basic module selection and build option
|
||||
selection tool called 'menuselect'. Run 'make menuselect' to make your choices.
|
||||
In this tool, you can disable building of modules that you don't care about,
|
||||
turn on/off global options for the build and see which modules will not
|
||||
(and cannot) be built because your system does not have the required external
|
||||
dependencies installed.
|
||||
|
||||
The resulting file from menuselect is called 'menuselect.makeopts'. Note that
|
||||
the resulting menuselect.makeopts file generally contains which modules *not*
|
||||
to build. The modules listed in this file indicate which modules have unmet
|
||||
dependencies, a present conflict, or have been disabled by the user in the
|
||||
menuselect interface. Compiler Flags can also be set in the menuselect
|
||||
interface. In this case, the resulting file contains which CFLAGS are in use,
|
||||
not which ones are not in use.
|
||||
|
||||
If you would like to save your choices and have them applied against all
|
||||
builds, the file can be copied to '~/.asterisk.makeopts' or
|
||||
'/etc/asterisk.makeopts'.
|
||||
|
||||
Build Process (Makefile targets):
|
||||
|
||||
The 'valgrind' and 'dont-optimize' targets have been removed; their functionality
|
||||
is available by enabling the DONT_OPTIMIZE setting in the 'Compiler Flags' menu
|
||||
in the menuselect tool.
|
||||
|
||||
It is now possible to run most make targets against a single subdirectory; from
|
||||
the top level directory, for example, 'make channels' will run 'make all' in the
|
||||
'channels' subdirectory. This also is true for 'clean', 'distclean' and 'depend'.
|
||||
|
||||
Sound (prompt) and Music On Hold files:
|
||||
|
||||
Beginning with Asterisk 1.4, the sound files and music on hold files supplied for
|
||||
use with Asterisk have been replaced with new versions produced from high quality
|
||||
master recordings, and are available in three languages (English, French and
|
||||
Spanish) and in five formats (WAV (uncompressed), mu-Law, a-Law, GSM and G.729).
|
||||
In addition, the music on hold files provided by opsound.org Music are now available
|
||||
in the same five formats, but no longer available in MP3 format.
|
||||
|
||||
The Asterisk 1.4 tarball packages will only include English prompts in GSM format,
|
||||
(as were supplied with previous releases) and the opsound.org MOH files in WAV format.
|
||||
All of the other variations can be installed by running 'make menuselect' and
|
||||
selecting the packages you wish to install; when you run 'make install', those
|
||||
packages will be downloaded and installed along with the standard files included
|
||||
in the tarball.
|
||||
|
||||
If for some reason you expect to not have Internet access at the time you will be
|
||||
running 'make install', you can make your package selections using menuselect and
|
||||
then run 'make sounds' to download (only) the sound packages; this will leave the
|
||||
sound packages in the 'sounds' subdirectory to be used later during installation.
|
||||
|
||||
WARNING: Asterisk 1.4 supports a new layout for sound files in multiple languages;
|
||||
instead of the alternate-language files being stored in subdirectories underneath
|
||||
the existing files (for French, that would be digits/fr, letters/fr, phonetic/fr,
|
||||
etc.) the new layout creates one directory under /var/lib/asterisk/sounds for the
|
||||
language itself, then places all the sound files for that language under that
|
||||
directory and its subdirectories. This is the layout that will be created if you
|
||||
select non-English languages to be installed via menuselect, HOWEVER Asterisk does
|
||||
not default to this layout and will not find the files in the places it expects them
|
||||
to be. If you wish to use this layout, make sure you put 'languageprefix=yes' in your
|
||||
/etc/asterisk/asterisk.conf file, so that Asterisk will know how the files were
|
||||
installed.
|
||||
|
||||
PBX Core:
|
||||
|
||||
* The (very old and undocumented) ability to use BYEXTENSION for dialing
|
||||
instead of ${EXTEN} has been removed.
|
||||
|
||||
* Builtin (res_features) transfer functionality attempts to use the context
|
||||
defined in TRANSFER_CONTEXT variable of the transferer channel first. If
|
||||
not set, it uses the transferee variable. If not set in any channel, it will
|
||||
attempt to use the last non macro context. If not possible, it will default
|
||||
to the current context.
|
||||
|
||||
* The autofallthrough setting introduced in Asterisk 1.2 now defaults to 'yes';
|
||||
if your dialplan relies on the ability to 'run off the end' of an extension
|
||||
and wait for a new extension without using WaitExten() to accomplish that,
|
||||
you will need set autofallthrough to 'no' in your extensions.conf file.
|
||||
|
||||
Command Line Interface:
|
||||
|
||||
* 'show channels concise', designed to be used by applications that will parse
|
||||
its output, previously used ':' characters to separate fields. However, some
|
||||
of those fields can easily contain that character, making the output not
|
||||
parseable. The delimiter has been changed to '!'.
|
||||
|
||||
Applications:
|
||||
|
||||
* In previous Asterisk releases, many applications would jump to priority n+101
|
||||
to indicate some kind of status or error condition. This functionality was
|
||||
marked deprecated in Asterisk 1.2. An option to disable it was provided with
|
||||
the default value set to 'on'. The default value for the global priority
|
||||
jumping option is now 'off'.
|
||||
|
||||
* The applications Cut, Sort, DBGet, DBPut, SetCIDNum, SetCIDName, SetRDNIS,
|
||||
AbsoluteTimeout, DigitTimeout, ResponseTimeout, SetLanguage, GetGroupCount,
|
||||
and GetGroupMatchCount were all deprecated in version 1.2, and therefore have
|
||||
been removed in this version. You should use the equivalent dialplan
|
||||
function in places where you have previously used one of these applications.
|
||||
|
||||
* The application SetGlobalVar has been deprecated. You should replace uses
|
||||
of this application with the following combination of Set and GLOBAL():
|
||||
Set(GLOBAL(name)=value). You may also access global variables exclusively by
|
||||
using the GLOBAL() dialplan function, instead of relying on variable
|
||||
interpolation falling back to globals when no channel variable is set.
|
||||
|
||||
* The application SetVar has been renamed to Set. The syntax SetVar was marked
|
||||
deprecated in version 1.2 and is no longer recognized in this version. The
|
||||
use of Set with multiple argument pairs has also been deprecated. Please
|
||||
separate each name/value pair into its own dialplan line.
|
||||
|
||||
* app_read has been updated to use the newer options codes, using "skip" or
|
||||
"noanswer" will not work. Use s or n. Also there is a new feature i, for
|
||||
using indication tones, so typing in skip would give you unexpected results.
|
||||
|
||||
* OSPAuth is added to authenticate OSP tokens in in_bound call setup messages.
|
||||
|
||||
* The CONNECT event in the queue_log from app_queue now has a second field
|
||||
in addition to the holdtime field. It contains the unique ID of the
|
||||
queue member channel that is taking the call. This is useful when trying
|
||||
to link recording filenames back to a particular call from the queue.
|
||||
|
||||
* The old/current behavior of app_queue has a serial type behavior
|
||||
in that the queue will make all waiting callers wait in the queue
|
||||
even if there is more than one available member ready to take
|
||||
calls until the head caller is connected with the member they
|
||||
were trying to get to. The next waiting caller in line then
|
||||
becomes the head caller, and they are then connected with the
|
||||
next available member and all available members and waiting callers
|
||||
waits while this happens. This cycle continues until there are
|
||||
no more available members or waiting callers, whichever comes first.
|
||||
The new behavior, enabled by setting autofill=yes in queues.conf
|
||||
either at the [general] level to default for all queues or
|
||||
to set on a per-queue level, makes sure that when the waiting
|
||||
callers are connecting with available members in a parallel fashion
|
||||
until there are no more available members or no more waiting callers,
|
||||
whichever comes first. This is probably more along the lines of how
|
||||
one would expect a queue should work and in most cases, you will want
|
||||
to enable this new behavior. If you do not specify or comment out this
|
||||
option, it will default to "no" to keep backward compatability with the old
|
||||
behavior.
|
||||
|
||||
* Queues depend on the channel driver reporting the proper state
|
||||
for each member of the queue. To get proper signalling on
|
||||
queue members that use the SIP channel driver, you need to
|
||||
enable a call limit (could be set to a high value so it
|
||||
is not put into action) and also make sure that both inbound
|
||||
and outbound calls are accounted for.
|
||||
|
||||
Example:
|
||||
|
||||
[general]
|
||||
limitonpeer = yes
|
||||
|
||||
[peername]
|
||||
type=friend
|
||||
call-limit=10
|
||||
|
||||
|
||||
* The app_queue application now has the ability to use MixMonitor to
|
||||
record conversations queue members are having with queue callers. Please
|
||||
see configs/queues.conf.sample for more information on this option.
|
||||
|
||||
* The app_queue application strategy called 'roundrobin' has been deprecated
|
||||
for this release. Users are encouraged to use 'rrmemory' instead, since it
|
||||
provides more 'true' round-robin call delivery. For the Asterisk 1.6 release,
|
||||
'rrmemory' will be renamed 'roundrobin'.
|
||||
|
||||
* The app_queue application option called 'monitor-join' has been deprecated
|
||||
for this release. Users are encouraged to use 'monitor-type=mixmonitor' instead,
|
||||
since it provides the same functionality but is not dependent on soxmix or some
|
||||
other external program in order to mix the audio.
|
||||
|
||||
* app_meetme: The 'm' option (monitor) is renamed to 'l' (listen only), and
|
||||
the 'm' option now provides the functionality of "initially muted".
|
||||
In practice, most existing dialplans using the 'm' flag should not notice
|
||||
any difference, unless the keypad menu is enabled, allowing the user
|
||||
to unmute themsleves.
|
||||
|
||||
* ast_play_and_record would attempt to cancel the recording if a DTMF
|
||||
'0' was received. This behavior was not documented in most of the
|
||||
applications that used ast_play_and_record and the return codes from
|
||||
ast_play_and_record weren't checked for properly.
|
||||
ast_play_and_record has been changed so that '0' no longer cancels a
|
||||
recording. If you want to allow DTMF digits to cancel an
|
||||
in-progress recording use ast_play_and_record_full which allows you
|
||||
to specify which DTMF digits can be used to accept a recording and
|
||||
which digits can be used to cancel a recording.
|
||||
|
||||
* ast_app_messagecount has been renamed to ast_app_inboxcount. There is now a
|
||||
new ast_app_messagecount function which takes a single context/mailbox/folder
|
||||
mailbox specification and returns the message count for that folder only.
|
||||
This addresses the deficiency of not being able to count the number of
|
||||
messages in folders other than INBOX and Old.
|
||||
|
||||
* The exit behavior of the AGI applications has changed. Previously, when
|
||||
a connection to an AGI server failed, the application would cause the channel
|
||||
to immediately stop dialplan execution and hangup. Now, the only time that
|
||||
the AGI applications will cause the channel to stop dialplan execution is
|
||||
when the channel itself requests hangup. The AGI applications now set an
|
||||
AGISTATUS variable which will allow you to find out whether running the AGI
|
||||
was successful or not.
|
||||
|
||||
Previously, there was no way to handle the case where Asterisk was unable to
|
||||
locally execute an AGI script for some reason. In this case, dialplan
|
||||
execution will continue as it did before, but the AGISTATUS variable will be
|
||||
set to "FAILURE".
|
||||
|
||||
A locally executed AGI script can now exit with a non-zero exit code and this
|
||||
failure will be detected by Asterisk. If an AGI script exits with a non-zero
|
||||
exit code, the AGISTATUS variable will be set to "FAILURE" as opposed to
|
||||
"SUCCESS".
|
||||
|
||||
* app_voicemail: The ODBC_STORAGE capability now requires the extended table format
|
||||
previously used only by EXTENDED_ODBC_STORAGE. This means that you will need to update
|
||||
your table format using the schema provided in doc/odbcstorage.txt
|
||||
|
||||
* app_waitforsilence: Fixes have been made to this application which changes the
|
||||
default behavior with how quickly it returns. You can maintain "old-style" behavior
|
||||
with the addition/use of a third "timeout" parameter.
|
||||
Please consult the application documentation and make changes to your dialplan
|
||||
if appropriate.
|
||||
|
||||
Manager:
|
||||
|
||||
* After executing the 'status' manager action, the "Status" manager events
|
||||
included the header "CallerID:" which was actually only the CallerID number,
|
||||
and not the full CallerID string. This header has been renamed to
|
||||
"CallerIDNum". For compatibility purposes, the CallerID parameter will remain
|
||||
until after the release of 1.4, when it will be removed. Please use the time
|
||||
during the 1.4 release to make this transition.
|
||||
|
||||
* The AgentConnect event now has an additional field called "BridgedChannel"
|
||||
which contains the unique ID of the queue member channel that is taking the
|
||||
call. This is useful when trying to link recording filenames back to
|
||||
a particular call from the queue.
|
||||
|
||||
* app_userevent has been modified to always send Event: UserEvent with the
|
||||
additional header UserEvent: <userspec>. Also, the Channel and UniqueID
|
||||
headers are not automatically sent, unless you specify them as separate
|
||||
arguments. Please see the application help for the new syntax.
|
||||
|
||||
* app_meetme: Mute and Unmute events are now reported via the Manager API.
|
||||
Native Manager API commands MeetMeMute and MeetMeUnmute are provided, which
|
||||
are easier to use than "Action Command:". The MeetMeStopTalking event has
|
||||
also been deprecated in favor of the already existing MeetmeTalking event
|
||||
with a "Status" of "on" or "off" added.
|
||||
|
||||
* OriginateFailure and OriginateSuccess events were replaced by event
|
||||
OriginateResponse with a header named "Response" to indicate success or
|
||||
failure
|
||||
|
||||
Variables:
|
||||
|
||||
* The builtin variables ${CALLERID}, ${CALLERIDNAME}, ${CALLERIDNUM},
|
||||
${CALLERANI}, ${DNID}, ${RDNIS}, ${DATETIME}, ${TIMESTAMP}, ${ACCOUNTCODE},
|
||||
and ${LANGUAGE} have all been deprecated in favor of their related dialplan
|
||||
functions. You are encouraged to move towards the associated dialplan
|
||||
function, as these variables will be removed in a future release.
|
||||
|
||||
* The CDR-CSV variables uniqueid, userfield, and basing time on GMT are now
|
||||
adjustable from cdr.conf, instead of recompiling.
|
||||
|
||||
* OSP applications exports several new variables, ${OSPINHANDLE},
|
||||
${OSPOUTHANDLE}, ${OSPINTOKEN}, ${OSPOUTTOKEN}, ${OSPCALLING},
|
||||
${OSPINTIMELIMIT}, and ${OSPOUTTIMELIMIT}
|
||||
|
||||
* Builtin transfer functionality sets the variable ${TRANSFERERNAME} in the new
|
||||
created channel. This variables holds the channel name of the transferer.
|
||||
|
||||
* The dial plan variable PRI_CAUSE will be removed from future versions
|
||||
of Asterisk.
|
||||
It is replaced by adding a cause value to the hangup() application.
|
||||
|
||||
Functions:
|
||||
|
||||
* The function ${CHECK_MD5()} has been deprecated in favor of using an
|
||||
expression: $[${MD5(<string>)} = ${saved_md5}].
|
||||
|
||||
* The 'builtin' functions that used to be combined in pbx_functions.so are
|
||||
now built as separate modules. If you are not using 'autoload=yes' in your
|
||||
modules.conf file then you will need to explicitly load the modules that
|
||||
contain the functions you want to use.
|
||||
|
||||
* The ENUMLOOKUP() function with the 'c' option (for counting the number of
|
||||
records), but the lookup fails to match any records, the returned value will
|
||||
now be "0" instead of blank.
|
||||
|
||||
* The REALTIME() function is now available in version 1.4 and app_realtime has
|
||||
been deprecated in favor of the new function. app_realtime will be removed
|
||||
completely with the version 1.6 release so please take the time between
|
||||
releases to make any necessary changes
|
||||
|
||||
* The QUEUEAGENTCOUNT() function has been deprecated in favor of
|
||||
QUEUE_MEMBER_COUNT().
|
||||
|
||||
The IAX2 channel:
|
||||
|
||||
* It is possible that previous configurations depended on the order in which
|
||||
peers and users were specified in iax.conf for forcing the order in which
|
||||
chan_iax2 matched against them. This behavior is going away and is considered
|
||||
deprecated in this version. Avoid having ambiguous peer and user entries and
|
||||
to make things easy on yourself, always set the "username" option for users
|
||||
so that the remote end can match on that exactly instead of trying to infer
|
||||
which user you want based on host.
|
||||
|
||||
If you would like to go ahead and use the new behavior which doesn't use the
|
||||
order in the config file to influence matching order, then change the
|
||||
MAX_PEER_BUCKETS define in chan_iax2.c to a value greater than one. An
|
||||
example is provided there. By changing this, you will get *much* better
|
||||
performance on systems that do a lot of peer and user lookups as they will be
|
||||
stored in memory in a much more efficient manner.
|
||||
|
||||
* The "mailboxdetail" option has been deprecated. Previously, if this option
|
||||
was not enabled, the 2 byte MSGCOUNT information element would be set to all
|
||||
1's to indicate there there is some number of messages waiting. With this
|
||||
option enabled, the number of new messages were placed in one byte and the
|
||||
number of old messages are placed in the other. This is now the default
|
||||
(and the only) behavior.
|
||||
|
||||
The SIP channel:
|
||||
|
||||
* The "incominglimit" setting is replaced by the "call-limit" setting in
|
||||
sip.conf.
|
||||
|
||||
* OSP support code is removed from SIP channel to OSP applications. ospauth
|
||||
option in sip.conf is removed to osp.conf as authpolicy. allowguest option
|
||||
in sip.conf cannot be set as osp anymore.
|
||||
|
||||
* The Asterisk RTP stack has been changed in regards to RFC2833 reception
|
||||
and transmission. Packets will now be sent with proper duration instead of all
|
||||
at once. If you are receiving calls from a pre-1.4 Asterisk installation you
|
||||
will want to turn on the rfc2833compensate option. Without this option your
|
||||
DTMF reception may act poorly.
|
||||
|
||||
* The $SIPUSERAGENT dialplan variable is deprecated and will be removed
|
||||
in coming versions of Asterisk. Please use the dialplan function
|
||||
SIPCHANINFO(useragent) instead.
|
||||
|
||||
* The ALERT_INFO dialplan variable is deprecated and will be removed
|
||||
in coming versions of Asterisk. Please use the dialplan application
|
||||
sipaddheader() to add the "Alert-Info" header to the outbound invite.
|
||||
|
||||
* The "canreinvite" option has changed. canreinvite=yes used to disable
|
||||
re-invites if you had NAT=yes. In 1.4, you need to set canreinvite=nonat
|
||||
to disable re-invites when NAT=yes. This is propably what you want.
|
||||
The settings are now: "yes", "no", "nonat", "update". Please consult
|
||||
sip.conf.sample for detailed information.
|
||||
|
||||
The Zap channel:
|
||||
|
||||
* Support for MFC/R2 has been removed, as it has not been functional for some
|
||||
time and it has no maintainer.
|
||||
|
||||
The Agent channel:
|
||||
|
||||
* Callback mode (AgentCallbackLogin) is now deprecated, since the entire function
|
||||
it provided can be done using dialplan logic, without requiring additional
|
||||
channel and module locks (which frequently caused deadlocks). An example of
|
||||
how to do this using AEL dialplan is in doc/queues-with-callback-members.txt.
|
||||
|
||||
The G726-32 codec:
|
||||
|
||||
* It has been determined that previous versions of Asterisk used the wrong codeword
|
||||
packing order for G726-32 data. This version supports both available packing orders,
|
||||
and can transcode between them. It also now selects the proper order when
|
||||
negotiating with a SIP peer based on the codec name supplied in the SDP. However,
|
||||
there are existing devices that improperly request one order and then use another;
|
||||
Sipura and Grandstream ATAs are known to do this, and there may be others. To
|
||||
be able to continue to use these devices with this version of Asterisk and the
|
||||
G726-32 codec, a configuration parameter called 'g726nonstandard' has been added
|
||||
to sip.conf, so that Asterisk can use the packing order expected by the device (even
|
||||
though it requested a different order). In addition, the internal format number for
|
||||
G726-32 has been changed, and the old number is now assigned to AAL2-G726-32. The
|
||||
result of this is that this version of Asterisk will be able to interoperate over
|
||||
IAX2 with older versions of Asterisk, as long as this version is told to allow
|
||||
'g726aal2' instead of 'g726' as the codec for the call.
|
||||
|
||||
Installation:
|
||||
|
||||
* On BSD systems, the installation directories have changed to more "FreeBSDish"
|
||||
directories. On startup, Asterisk will look for the main configuration in
|
||||
/usr/local/etc/asterisk/asterisk.conf
|
||||
If you have an old installation, you might want to remove the binaries and
|
||||
move the configuration files to the new locations. The following directories
|
||||
are now default:
|
||||
ASTLIBDIR /usr/local/lib/asterisk
|
||||
ASTVARLIBDIR /usr/local/share/asterisk
|
||||
ASTETCDIR /usr/local/etc/asterisk
|
||||
ASTBINDIR /usr/local/bin/asterisk
|
||||
ASTSBINDIR /usr/local/sbin/asterisk
|
||||
|
||||
Music on Hold:
|
||||
|
||||
* The music on hold handling has been changed in some significant ways in hopes
|
||||
to make it work in a way that is much less confusing to users. Behavior will
|
||||
not change if the same configuration is used from older versions of Asterisk.
|
||||
However, there are some new configuration options that will make things work
|
||||
in a way that makes more sense.
|
||||
|
||||
Previously, many of the channel drivers had an option called "musicclass" or
|
||||
something similar. This option set what music on hold class this channel
|
||||
would *hear* when put on hold. Some people expected (with good reason) that
|
||||
this option was to configure what music on hold class to play when putting
|
||||
the bridged channel on hold. This option has now been deprecated.
|
||||
|
||||
Two new music on hold related configuration options for channel drivers have
|
||||
been introduced. Some channel drivers support both options, some just one,
|
||||
and some support neither of them. Check the sample configuration files to see
|
||||
which options apply to which channel driver.
|
||||
|
||||
The "mohsuggest" option specifies which music on hold class to suggest to the
|
||||
bridged channel when putting them on hold. The only way that this class can
|
||||
be overridden is if the bridged channel has a specific music class set that
|
||||
was done in the dialplan using Set(CHANNEL(musicclass)=something).
|
||||
|
||||
The "mohinterpret" option is similar to the old "musicclass" option. It
|
||||
specifies which music on hold class this channel would like to listen to when
|
||||
put on hold. This music class is only effective if this channel has no music
|
||||
class set on it from the dialplan and the bridged channel putting this one on
|
||||
hold had no "mohsuggest" setting.
|
||||
|
||||
The IAX2 and Zap channel drivers have an additional feature for the
|
||||
"mohinterpret" option. If this option is set to "passthrough", then these
|
||||
channel drivers will pass through the HOLD message in signalling instead of
|
||||
starting music on hold on the channel. An example for how this would be
|
||||
useful is in an enterprise network of Asterisk servers. When one phone on one
|
||||
server puts a phone on a different server on hold, the remote server will be
|
||||
responsible for playing the hold music to its local phone that was put on
|
||||
hold instead of the far end server across the network playing the music.
|
||||
|
||||
CDR Records:
|
||||
|
||||
* The behavior of the "clid" field of the CDR has always been that it will
|
||||
contain the callerid ANI if it is set, or the callerid number if ANI was not
|
||||
set. When using the "callerid" option for various channel drivers, some
|
||||
would set ANI and some would not. This has been cleared up so that all
|
||||
channel drivers set ANI. If you would like to change the callerid number
|
||||
on the channel from the dialplan and have that change also show up in the
|
||||
CDR, then you *must* set CALLERID(ANI) as well as CALLERID(num).
|
||||
|
||||
API:
|
||||
|
||||
* There are some API functions that were not previously prefixed with the 'ast_'
|
||||
prefix but now are; these include the ADSI, ODBC and AGI interfaces. If you
|
||||
have a module that uses the services provided by res_adsi, res_odbc, or
|
||||
res_agi, you will need to add ast_ prefixes to the functions that you call
|
||||
from those modules.
|
||||
|
||||
Formats:
|
||||
|
||||
* format_wav: The GAIN preprocessor definition has been changed from 2 to 0
|
||||
in Asterisk 1.4. This change was made in response to user complaints of
|
||||
choppiness or the clipping of loud signal peaks. The GAIN preprocessor
|
||||
definition will be retained in Asterisk 1.4, but will be removed in a
|
||||
future release. The use of GAIN for the increasing of voicemail message
|
||||
volume should use the 'volgain' option in voicemail.conf
|
277
UPGRADE-1.6.txt
277
UPGRADE-1.6.txt
|
@ -1,277 +0,0 @@
|
|||
=========================================================
|
||||
===
|
||||
=== Information for upgrading from Asterisk 1.4 to 1.6
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also includes advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
===
|
||||
=========================================================
|
||||
|
||||
AEL:
|
||||
|
||||
* Macros are now implemented underneath with the Gosub() application.
|
||||
Heaven Help You if you wrote code depending on any aspect of this!
|
||||
Previous to 1.6, macros were implemented with the Macro() app, which
|
||||
provided a nice feature of auto-returning. The compiler will do its
|
||||
best to insert a Return() app call at the end of your macro if you did
|
||||
not include it, but really, you should make sure that all execution
|
||||
paths within your macros end in "return;".
|
||||
|
||||
* The conf2ael program is 'introduced' in this release; it is in a rather
|
||||
crude state, but deemed useful for making a first pass at converting
|
||||
extensions.conf code into AEL. More intelligence will come with time.
|
||||
|
||||
Core:
|
||||
|
||||
* The 'languageprefix' option in asterisk.conf is now deprecated, and
|
||||
the default sound file layout for non-English sounds is the 'new
|
||||
style' layout introduced in Asterisk 1.4 (and used by the automatic
|
||||
sound file installer in the Makefile).
|
||||
|
||||
* The ast_expr2 stuff has been modified to handle floating-point numbers.
|
||||
Numbers of the format D.D are now acceptable input for the expr parser,
|
||||
Where D is a string of base-10 digits. All math is now done in "long double",
|
||||
if it is available on your compiler/architecture. This was half-way between
|
||||
a bug-fix (because the MATH func returns fp by default), and an enhancement.
|
||||
Also, for those counting on, or needing, integer operations, a series of
|
||||
'functions' were also added to the expr language, to allow several styles
|
||||
of rounding/truncation, along with a set of common floating point operations,
|
||||
like sin, cos, tan, log, pow, etc. The ability to call external functions
|
||||
like CDR(), etc. was also added, without having to use the ${...} notation.
|
||||
|
||||
* The delimiter passed to applications has been changed to the comma (','), as
|
||||
that is what people are used to using within extensions.conf. If you are
|
||||
using realtime extensions, you will need to translate your existing dialplan
|
||||
to use this separator. To use a literal comma, you need merely to escape it
|
||||
with a backslash ('\'). Another possible side effect is that you may need to
|
||||
remove the obscene level of backslashing that was necessary for the dialplan
|
||||
to work correctly in 1.4 and previous versions. This should make writing
|
||||
dialplans less painful in the future, albeit with the pain of a one-time
|
||||
conversion. If you would like to avoid this conversion immediately, set
|
||||
pbx_realtime=1.4 in the [compat] section of asterisk.conf. After
|
||||
transitioning, set pbx_realtime=1.6 in the same section.
|
||||
|
||||
* For the same purpose as above, you may set res_agi=1.4 in the [compat]
|
||||
section of asterisk.conf to continue to use the '|' delimiter in the EXEC
|
||||
arguments of AGI applications. After converting to use the ',' delimiter,
|
||||
change this option to res_agi=1.6.
|
||||
|
||||
* As a side effect of the application delimiter change, many places that used
|
||||
to need quotes in order to get the proper meaning are no longer required.
|
||||
You now only need to quote strings in configuration files if you literally
|
||||
want quotation marks within a string.
|
||||
|
||||
* Any applications run that contain the pipe symbol but not a comma symbol will
|
||||
get a warning printed to the effect that the application delimiter has changed.
|
||||
However, there are legitimate reasons why this might be useful in certain
|
||||
situations, so this warning can be turned off with the dontwarn option in
|
||||
asterisk.conf.
|
||||
|
||||
* The logger.conf option 'rotatetimestamp' has been deprecated in favor of
|
||||
'rotatestrategy'. This new option supports a 'rotate' strategy that more
|
||||
closely mimics the system logger in terms of file rotation.
|
||||
|
||||
* The concise versions of various CLI commands are now deprecated. We recommend
|
||||
using the manager interface (AMI) for application integration with Asterisk.
|
||||
|
||||
Voicemail:
|
||||
|
||||
* The voicemail configuration values 'maxmessage' and 'minmessage' have
|
||||
been changed to 'maxsecs' and 'minsecs' to clarify their purpose and
|
||||
to make them more distinguishable from 'maxmsgs', which sets folder
|
||||
size. The old variables will continue to work in this version, albeit
|
||||
with a deprecation warning.
|
||||
|
||||
* If you use any interface for modifying voicemail aside from the built in
|
||||
dialplan applications, then the option "pollmailboxes" *must* be set in
|
||||
voicemail.conf for message waiting indication (MWI) to work properly. This
|
||||
is because Voicemail notification is now event based instead of polling
|
||||
based. The channel drivers are no longer responsible for constantly manually
|
||||
checking mailboxes for changes so that they can send MWI information to users.
|
||||
Examples of situations that would require this option are web interfaces to
|
||||
voicemail or an email client in the case of using IMAP storage.
|
||||
|
||||
Applications:
|
||||
|
||||
|
||||
* ChanIsAvail() now has a 't' option, which allows the specified device
|
||||
to be queried for state without consulting the channel drivers. This
|
||||
performs mostly a 'ChanExists' sort of function.
|
||||
|
||||
* ChannelRedirect() will not terminate the channel that fails to do a
|
||||
channelredirect as it has done previously. Instead CHANNELREDIRECT_STATUS
|
||||
will reflect if the attempt was successful of not.
|
||||
|
||||
* SetCallerPres() has been replaced with the CALLERPRES() dialplan function
|
||||
and is now deprecated.
|
||||
|
||||
* DISA()'s fifth argument is now an options argument. If you have previously
|
||||
used 'NOANSWER' in this argument, you'll need to convert that to the new
|
||||
option 'n'.
|
||||
|
||||
* Macro() is now deprecated. If you need subroutines, you should use the
|
||||
Gosub()/Return() applications. To replace MacroExclusive(), we have
|
||||
introduced dialplan functions LOCK(), TRYLOCK(), and UNLOCK(). You may use
|
||||
these functions in any location where you desire to ensure that only one
|
||||
channel is executing that path at any one time. The Macro() applications
|
||||
are deprecated for performance reasons. However, since Macro() has been
|
||||
around for a long time and so many dialplans depend heavily on it, for the
|
||||
sake of backwards compatibility it will not be removed . It is also worth
|
||||
noting that using both Macro() and GoSub() at the same time is _heavily_
|
||||
discouraged.
|
||||
|
||||
* Read() now sets a READSTATUS variable on exit. It does NOT automatically
|
||||
return -1 (and hangup) anymore on error. If you want to hangup on error,
|
||||
you need to do so explicitly in your dialplan.
|
||||
|
||||
* Privacy() no longer uses privacy.conf, so any options must be specified
|
||||
directly in the application arguments.
|
||||
|
||||
* MusicOnHold application now has duration parameter which allows specifying
|
||||
timeout in seconds.
|
||||
|
||||
* WaitMusicOnHold application is now deprecated in favor of extended MusicOnHold.
|
||||
|
||||
* SetMusicOnHold is now deprecated. You should use Set(CHANNEL(musicclass)=...)
|
||||
instead.
|
||||
|
||||
* The arguments in ExecIf changed a bit, to be more like other applications.
|
||||
The syntax is now ExecIf(<cond>?appiftrue(args):appiffalse(args)).
|
||||
|
||||
* The behavior of the Set application now depends upon a compatibility option,
|
||||
set in asterisk.conf. To use the old 1.4 behavior, which allowed Set to take
|
||||
multiple key/value pairs, set app_set=1.4 in [compat] in asterisk.conf. To
|
||||
use the new behavior, which permits variables to be set with embedded commas,
|
||||
set app_set=1.6 in [compat] in asterisk.conf. Note that you can have both
|
||||
behaviors at the same time, if you switch to using MSet if you want the old
|
||||
behavior.
|
||||
|
||||
Dialplan Functions:
|
||||
|
||||
* QUEUE_MEMBER_COUNT() has been deprecated in favor of the QUEUE_MEMBER() function. For
|
||||
more information, issue a "show function QUEUE_MEMBER" from the CLI.
|
||||
|
||||
CDR:
|
||||
|
||||
* The cdr_sqlite module has been marked as deprecated in favor of
|
||||
cdr_sqlite3_custom. It will potentially be removed from the tree
|
||||
after Asterisk 1.6 is released.
|
||||
|
||||
* The cdr_odbc module now uses res_odbc to manage its connections. The
|
||||
username and password parameters in cdr_odbc.conf, therefore, are no
|
||||
longer used. The dsn parameter now points to an entry in res_odbc.conf.
|
||||
|
||||
* The uniqueid field in the core Asterisk structure has been changed from a
|
||||
maximum 31 character field to a 149 character field, to account for all
|
||||
possible values the systemname prefix could be. In the past, if the
|
||||
systemname was too long, the uniqueid would have been truncated.
|
||||
|
||||
* The cdr_tds module now supports all versions of FreeTDS that contain
|
||||
the db-lib frontend. It will also now log the userfield variable if
|
||||
the target database table contains a column for it.
|
||||
|
||||
Formats:
|
||||
|
||||
* format_wav: The GAIN preprocessor definition and source code that used it
|
||||
is removed. This change was made in response to user complaints of
|
||||
choppiness or the clipping of loud signal peaks. To increase the volume
|
||||
of voicemail messages, use the 'volgain' option in voicemail.conf
|
||||
|
||||
Channel Drivers:
|
||||
|
||||
* SIP: a small upgrade to support the "Record" button on the SNOM360,
|
||||
which sends a sip INFO message with a "Record: on" or "Record: off"
|
||||
header. If Asterisk is set up (via features.conf) to accept "One Touch Monitor"
|
||||
requests (by default, via '*1'), then the user-configured dialpad sequence
|
||||
is generated, and recording can be started and stopped via this button. The
|
||||
file names and formats are all controlled via the normal mechanisms. If the
|
||||
user has not configured the automon feature, the normal "415 Unsupported media type"
|
||||
is returned, and nothing is done.
|
||||
|
||||
* SIP: The "call-limit" option is marked as deprecated. It still works in this version of
|
||||
Asterisk, but will be removed in the following version. Please use the groupcount functions
|
||||
in the dialplan to enforce call limits. The "limitonpeer" configuration option is
|
||||
now renamed to "counteronpeer".
|
||||
|
||||
* SIP: The "username" option is now renamed to "defaultuser" to match "defaultip".
|
||||
These are used only before registration to call a peer with the uri
|
||||
sip:defaultuser@defaultip
|
||||
The "username" setting still work, but is deprecated and will not work in
|
||||
the next version of Asterisk.
|
||||
|
||||
* SIP: The old "insecure" options, deprecated in 1.4, have been removed.
|
||||
"insecure=very" should be changed to "insecure=port,invite"
|
||||
"insecure=yes" should be changed to "insecure=port"
|
||||
Be aware that some telephony providers show the invalid syntax in their
|
||||
sample configurations.
|
||||
|
||||
* chan_local.c: the comma delimiter inside the channel name has been changed to a
|
||||
semicolon, in order to make the Local channel driver compatible with the comma
|
||||
delimiter change in applications.
|
||||
|
||||
* H323: The "tos" setting has changed name to "tos_audio" and "cos" to "cos_audio"
|
||||
to be compatible with settings in sip.conf. The "tos" and "cos" configuration
|
||||
is deprecated and will stop working in the next release of Asterisk.
|
||||
|
||||
* Console: A new console channel driver, chan_console, has been added to Asterisk.
|
||||
This new module can not be loaded at the same time as chan_alsa or chan_oss. The
|
||||
default modules.conf only loads one of them (chan_oss by default). So, unless you
|
||||
have modified your modules.conf to not use the autoload option, then you will need
|
||||
to modify modules.conf to add another "noload" line to ensure that only one of
|
||||
these three modules gets loaded.
|
||||
|
||||
* DAHDI: The chan_zap module that supported PSTN interfaces using
|
||||
Zaptel has been renamed to chan_dahdi, and only supports the DAHDI
|
||||
telephony driver package for PSTN interfaces. See the
|
||||
Zaptel-to-DAHDI.txt file for more details on this transition.
|
||||
|
||||
* DAHDI: The "msdstrip" option has been deprecated, as it provides no value over
|
||||
the method of stripping digits in the dialplan using variable substring syntax.
|
||||
|
||||
Configuration:
|
||||
|
||||
* pbx_dundi.c: tos parameter changed to use new values. Old values like lowdelay,
|
||||
lowcost and other is not acceptable now. Look into qos.tex for description of
|
||||
this parameter.
|
||||
|
||||
* queues.conf: the queue-lessthan sound file option is no longer available, and the
|
||||
queue-round-seconds option no longer takes '1' as a valid parameter.
|
||||
|
||||
Manager:
|
||||
|
||||
* Manager has been upgraded to version 1.1 with a lot of changes.
|
||||
Please check doc/manager_1_1.txt for information
|
||||
|
||||
* The IAXpeers command output has been changed to more closely resemble the
|
||||
output of the SIPpeers command.
|
||||
|
||||
* cdr_manager now reports at the "cdr" level, not at "call" You may need to
|
||||
change your manager.conf to add the level to existing AMI users, if they
|
||||
want to see the CDR events generated.
|
||||
|
||||
* The Originate command now requires the Originate write permission. For
|
||||
Originate with the Application parameter, you need the additional System
|
||||
privilege if you want to do anything that calls out to a subshell.
|
||||
|
||||
iLBC Codec:
|
||||
|
||||
* Previously, the Asterisk source code distribution included the iLBC
|
||||
encoder/decoder source code, from Global IP Solutions
|
||||
(http://www.gipscorp.com). This code is not licensed for
|
||||
distribution, and thus has been removed from the Asterisk source
|
||||
code distribution. If you wish to use codec_ilbc to support iLBC
|
||||
channels in Asterisk, you can run the contrib/scripts/get_ilbc_source.sh
|
||||
script to download the source and put it in the proper place in
|
||||
the Asterisk build tree. Once that is done you can follow your normal
|
||||
steps of building Asterisk. You will need to run 'menuselect' and enable
|
||||
the iLBC codec in the 'Codec Translators' category.
|
343
UPGRADE-1.8.txt
343
UPGRADE-1.8.txt
|
@ -1,343 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also includes advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
===
|
||||
===========================================================
|
||||
|
||||
From 1.8.13 to 1.8.14:
|
||||
* permitdirectmedia/denydirectmedia now controls whether peers can be
|
||||
bridged via directmedia by comparing the ACL to the bridging peer's
|
||||
address rather than its own address.
|
||||
|
||||
From 1.8.12 to 1.8.13:
|
||||
* The complex processor detection and optimization has been removed from
|
||||
the makefile in favor of using native optimization suppport when available.
|
||||
BUILD_NATIVE can be disabled via menuselect under "Compiler Flags".
|
||||
|
||||
From 1.8.10 to 1.8.11:
|
||||
|
||||
* If no transport is specified in sip.conf, transport will default to UDP.
|
||||
Also, if multiple transport= lines are used, only the last will be used.
|
||||
|
||||
From 1.6.2 to 1.8:
|
||||
|
||||
* chan_sip no longer sets HASH(SIP_CAUSE,<chan name>) on channels by default.
|
||||
This must now be enabled by setting 'sipstorecause' to 'yes' in sip.conf.
|
||||
This carries a performance penalty.
|
||||
|
||||
* Asterisk now requires libpri 1.4.11+ for PRI support.
|
||||
|
||||
* A couple of CLI commands in res_ais were changed back to their original form:
|
||||
"ais show clm members" --> "ais clm show members"
|
||||
"ais show evt event channels" --> "ais evt show event channels"
|
||||
|
||||
* The default value for 'autofill' and 'shared_lastcall' in queues.conf has
|
||||
been changed to 'yes'.
|
||||
|
||||
* The default value for the alwaysauthreject option in sip.conf has been changed
|
||||
from "no" to "yes".
|
||||
|
||||
* The behavior of the 'parkedcallstimeout' has changed slightly. The formulation
|
||||
of the extension name that a timed out parked call is delivered to when this
|
||||
option is set to 'no' was modified such that instead of converting '/' to '0',
|
||||
the '/' is converted to an underscore '_'. See the updated documentation in
|
||||
features.conf.sample for more information on the behavior of the
|
||||
'parkedcallstimeout' option.
|
||||
|
||||
* Asterisk-addons no longer exists as an independent package. Those modules
|
||||
now live in the addons directory of the main Asterisk source tree. They
|
||||
are not enabled by default. For more information about why modules live in
|
||||
addons, see README-addons.txt.
|
||||
|
||||
* The rarely used 'event_log' and LOG_EVENT channel have been removed; the few
|
||||
users of this channel in the tree have been converted to LOG_NOTICE or removed
|
||||
(in cases where the same message was already generated to another channel).
|
||||
|
||||
* The usage of RTP inside of Asterisk has now become modularized. This means
|
||||
the Asterisk RTP stack now exists as a loadable module, res_rtp_asterisk.
|
||||
If you are not using autoload=yes in modules.conf you will need to ensure
|
||||
it is set to load. If not, then any module which uses RTP (such as chan_sip)
|
||||
will not be able to send or receive calls.
|
||||
|
||||
* The app_dahdiscan.c file has been removed, but the dialplan app DAHDIScan still
|
||||
remains. It now exists within app_chanspy.c and retains the exact same
|
||||
functionality as before.
|
||||
|
||||
* The default behavior for Set, AGI, and pbx_realtime has been changed to implement
|
||||
1.6 behavior by default, if there is no [compat] section in asterisk.conf. In
|
||||
prior versions, the behavior defaulted to 1.4 behavior, to assist in upgrades.
|
||||
Specifically, that means that pbx_realtime and res_agi expect you to use commas
|
||||
to separate arguments in applications, and Set only takes a single pair of
|
||||
a variable name/value. The old 1.4 behavior may still be obtained by setting
|
||||
app_set, pbx_realtime, and res_agi each to 1.4 in the [compat] section of
|
||||
asterisk.conf.
|
||||
|
||||
* The PRI channels in chan_dahdi can no longer change the channel name if a
|
||||
different B channel is selected during call negotiation. To prevent using
|
||||
the channel name to infer what B channel a call is using and to avoid name
|
||||
collisions, the channel name format is changed.
|
||||
The new channel naming for PRI channels is:
|
||||
DAHDI/i<span>/<number>[:<subaddress>]-<sequence-number>
|
||||
|
||||
* Added CHANNEL(dahdi_span), CHANNEL(dahdi_channel), and CHANNEL(dahdi_type)
|
||||
so the dialplan can determine the B channel currently in use by the channel.
|
||||
Use CHANNEL(no_media_path) to determine if the channel even has a B channel.
|
||||
|
||||
* Added AMI event DAHDIChannel to associate a DAHDI channel with an Asterisk
|
||||
channel so AMI applications can passively determine the B channel currently
|
||||
in use. Calls with "no-media" as the DAHDIChannel do not have an associated
|
||||
B channel. No-media calls are either on hold or call-waiting.
|
||||
|
||||
* The ChanIsAvail application has been changed so the AVAILSTATUS variable
|
||||
no longer contains both the device state and cause code. The cause code
|
||||
is now available in the AVAILCAUSECODE variable. If existing dialplan logic
|
||||
is written to expect AVAILSTATUS to contain the cause code it needs to be
|
||||
changed to use AVAILCAUSECODE.
|
||||
|
||||
* ExternalIVR will now send Z events for invalid or missing files, T events
|
||||
now include the interrupted file and bugs in argument parsing have been
|
||||
fixed so there may be arguments specified in incorrect ways that were
|
||||
working that will no longer work. Please see
|
||||
https://wiki.asterisk.org/wiki/display/AST/External+IVR+Interface for details.
|
||||
|
||||
* OSP lookup application changes following variable names:
|
||||
OSPPEERIP to OSPINPEERIP
|
||||
OSPTECH to OSPOUTTECH
|
||||
OSPDEST to OSPDESTINATION
|
||||
OSPCALLING to OSPOUTCALLING
|
||||
OSPCALLED to OSPOUTCALLED
|
||||
OSPRESULTS to OSPDESTREMAILS
|
||||
|
||||
* The Manager event 'iax2 show peers' output has been updated. It now has a
|
||||
similar output of 'sip show peers'.
|
||||
|
||||
* VoiceMailMain and VMAuthenticate, if a '*' is entered in the first position
|
||||
of a Mailbox or Password, will, if it exists, jump to the 'a' extension in
|
||||
the current dialplan context.
|
||||
|
||||
* The CALLERPRES() dialplan function is deprecated in favor of
|
||||
CALLERID(num-pres) and CALLERID(name-pres).
|
||||
|
||||
* Environment variables that start with "AST_" are reserved to the system and
|
||||
may no longer be set from the dialplan.
|
||||
|
||||
* When a call is redirected inside of a Dial, the app and appdata fields of the
|
||||
CDR will now be set to "AppDial" and "(Outgoing Line)" instead of being blank.
|
||||
|
||||
* The CDR handling of billsec and duration field has changed. If your table
|
||||
definition specifies those fields as float,double or similar they will now
|
||||
be logged with microsecond accuracy instead of a whole integer.
|
||||
|
||||
* chan_sip will no longer set up a local call forward when receiving a
|
||||
482 Loop Detected response. The dialplan will just continue from where it
|
||||
left off.
|
||||
|
||||
* The 'stunaddr' option has been removed from chan_sip. This feature did not
|
||||
behave as expected, had no correct use case, and was not RFC compliant. The
|
||||
removal of this feature will hopefully be followed by a correct RFC compliant
|
||||
STUN implementation in chan_sip in the future.
|
||||
|
||||
* The default value for the pedantic option in sip.conf has been changed
|
||||
from "no" to "yes".
|
||||
|
||||
* The ConnectedLineNum and ConnectedLineName headers were added to many AMI
|
||||
events/responses if the CallerIDNum/CallerIDName headers were also present.
|
||||
The addition of connected line support changes the behavior of the channel
|
||||
caller ID somewhat. The channel caller ID value no longer time shares with
|
||||
the connected line ID on outgoing call legs. The timing of some AMI
|
||||
events/responses output the connected line ID as caller ID. These party ID's
|
||||
are now separate.
|
||||
|
||||
* The Dial application d and H options do not automatically answer the call
|
||||
anymore. It broke DTMF attended transfers. Since many SIP and ISDN phones
|
||||
cannot send DTMF before a call is connected, you need to answer the call
|
||||
leg to those phones before using Dial with these options for them to have
|
||||
any effect before the dialed party answers.
|
||||
|
||||
* The outgoing directory (where .call files are read) now uses inotify to
|
||||
detect file changes instead of polling the directory on a regular basis.
|
||||
If your outgoing folder is on a NFS mount or another network file system,
|
||||
changes to the files will not be detected. You can revert to polling the
|
||||
directory by specifying --without-inotify to configure before compiling.
|
||||
|
||||
* The 'sipusers' realtime table has been removed completely. Use the 'sippeers'
|
||||
table with type 'user' for user type objects.
|
||||
|
||||
* The sip.conf allowoverlap option now accepts 'dtmf' as a value. If you
|
||||
are using the early media DTMF overlap dialing method you now need to set
|
||||
allowoverlap=dtmf.
|
||||
|
||||
From 1.6.1 to 1.6.2:
|
||||
|
||||
* SIP no longer sends the 183 progress message for early media by
|
||||
default. Applications requiring early media should use the
|
||||
progress() dialplan app to generate the progress message.
|
||||
|
||||
* The firmware for the IAXy has been removed from Asterisk. It can be
|
||||
downloaded from http://downloads.digium.com/pub/iaxy/. To have Asterisk
|
||||
install the firmware into its proper location, place the firmware in the
|
||||
contrib/firmware/iax/ directory in the Asterisk source tree before running
|
||||
"make install".
|
||||
|
||||
* T.38 FAX error correction mode can no longer be configured in udptl.conf;
|
||||
instead, it is configured on a per-peer (or global) basis in sip.conf, with
|
||||
the same default as was present in udptl.conf.sample.
|
||||
|
||||
* T.38 FAX maximum datagram size can no longer be configured in updtl.conf;
|
||||
instead, it is either supplied by the application servicing the T.38 channel
|
||||
(for a FAX send or receive) or calculated from the bridged endpoint's
|
||||
maximum datagram size (for a T.38 FAX passthrough call). In addition, sip.conf
|
||||
allows for overriding the value supplied by a remote endpoint, which is useful
|
||||
when T.38 connections are made to gateways that supply incorrectly-calculated
|
||||
maximum datagram sizes.
|
||||
|
||||
* There have been some changes to the IAX2 protocol to address the security
|
||||
concerns documented in the security advisory AST-2009-006. Please see the
|
||||
IAX2 security document, doc/IAX2-security.pdf, for information regarding
|
||||
backwards compatibility with versions of Asterisk that do not contain these
|
||||
changes to IAX2.
|
||||
|
||||
* The 'canreinvite' option support by the SIP, MGCP and Skinny channel drivers
|
||||
has been renamed to 'directmedia', to better reflect what it actually does.
|
||||
In the case of SIP, there are still re-INVITEs issued for T.38 negotiation,
|
||||
starting and stopping music-on-hold, and other reasons, and the 'canreinvite'
|
||||
option never had any effect on these cases, it only affected the re-INVITEs
|
||||
used for direct media path setup. For MGCP and Skinny, the option was poorly
|
||||
named because those protocols don't even use INVITE messages at all. For
|
||||
backwards compatibility, the old option is still supported in both normal
|
||||
and Realtime configuration files, but all of the sample configuration files,
|
||||
Realtime/LDAP schemas, and other documentation refer to it using the new name.
|
||||
|
||||
* The default console now will use colors according to the default background
|
||||
color, instead of forcing the background color to black. If you are using a
|
||||
light colored background for your console, you may wish to use the option
|
||||
flag '-W' to present better color choices for the various messages. However,
|
||||
if you'd prefer the old method of forcing colors to white text on a black
|
||||
background, the compatibility option -B is provided for this purpose.
|
||||
|
||||
* SendImage() no longer hangs up the channel on transmission error or on
|
||||
any other error; in those cases, a FAILURE status is stored in
|
||||
SENDIMAGESTATUS and dialplan execution continues. The possible
|
||||
return values stored in SENDIMAGESTATUS are: SUCCESS, FAILURE, and
|
||||
UNSUPPORTED. ('OK' has been replaced with 'SUCCESS', and 'NOSUPPORT'
|
||||
has been replaced with 'UNSUPPORTED'). This change makes the
|
||||
SendImage application more consistent with other applications.
|
||||
|
||||
* skinny.conf now has separate sections for lines and devices.
|
||||
Please have a look at configs/skinny.conf.sample and update
|
||||
your skinny.conf.
|
||||
|
||||
* Queue names previously were treated in a case-sensitive manner,
|
||||
meaning that queues with names like "sales" and "sALeS" would be
|
||||
seen as unique queues. The parsing logic has changed to use
|
||||
case-insensitive comparisons now when originally hashing based on
|
||||
queue names, meaning that now the two queues mentioned as examples
|
||||
earlier will be seen as having the same name.
|
||||
|
||||
* The SPRINTF() dialplan function has been moved into its own module,
|
||||
func_sprintf, and is no longer included in func_strings. If you use this
|
||||
function and do not use 'autoload=yes' in modules.conf, you will need
|
||||
to explicitly load func_sprintf for it to be available.
|
||||
|
||||
* The res_indications module has been removed. Its functionality was important
|
||||
enough that most of it has been moved into the Asterisk core.
|
||||
Two applications previously provided by res_indications, PlayTones and
|
||||
StopPlayTones, have been moved into a new module, app_playtones.
|
||||
|
||||
* Support for Taiwanese was incorrectly supported with the "tw" language code.
|
||||
In reality, the "tw" language code is reserved for the Twi language, native
|
||||
to Ghana. If you were previously using the "tw" language code, you should
|
||||
switch to using either "zh" (for Mandarin Chinese) or "zh_TW" for Taiwan
|
||||
specific localizations. Additionally, "mx" should be changed to "es_MX",
|
||||
Georgian was incorrectly specified as "ge" but should be "ka", and Czech is
|
||||
"cs", not "cz".
|
||||
|
||||
* DAHDISendCallreroutingFacility() parameters are now comma-separated,
|
||||
instead of the old pipe.
|
||||
|
||||
* res_jabber: autoprune has been disabled by default, to avoid misconfiguration
|
||||
that would end up being interpreted as a bug once Asterisk started removing
|
||||
the contacts from a user list.
|
||||
|
||||
* The cdr.conf file must exist and be configured correctly in order for CDR
|
||||
records to be written.
|
||||
|
||||
* cdr_pgsql now assumes the encoding of strings it is handed are in LATIN9,
|
||||
which should cover most uses of the extended ASCII set. If your strings
|
||||
use a different encoding in Asterisk, the "encoding" parameter may be set
|
||||
to specify the correct character set.
|
||||
|
||||
From 1.6.0.1 to 1.6.1:
|
||||
|
||||
* The ast_agi_register_multiple() and ast_agi_unregister_multiple()
|
||||
API calls were added in 1.6.0, so that modules that provide multiple
|
||||
AGI commands could register/unregister them all with a single
|
||||
step. However, these API calls were not implemented properly, and did
|
||||
not allow the caller to know whether registration or unregistration
|
||||
succeeded or failed. They have been redefined to now return success
|
||||
or failure, but this means any code using these functions will need
|
||||
be recompiled after upgrading to a version of Asterisk containing
|
||||
these changes. In addition, the source code using these functions
|
||||
should be reviewed to ensure it can properly react to failure
|
||||
of registration or unregistration of its API commands.
|
||||
|
||||
* The ast_agi_fdprintf() API call has been renamed to ast_agi_send()
|
||||
to better match what it really does, and the argument order has been
|
||||
changed to be consistent with other API calls that perform similar
|
||||
operations.
|
||||
|
||||
From 1.6.0.x to 1.6.1:
|
||||
|
||||
* In previous versions of Asterisk, due to the way objects were arranged in
|
||||
memory by chan_sip, the order of entries in sip.conf could be adjusted to
|
||||
control the behavior of matching against peers and users. The way objects
|
||||
are managed has been significantly changed for reasons involving performance
|
||||
and stability. A side effect of these changes is that the order of entries
|
||||
in sip.conf can no longer be relied upon to control behavior.
|
||||
|
||||
* The following core commands dealing with dialplan have been deprecated: 'core
|
||||
show globals', 'core set global' and 'core set chanvar'. Use the equivalent
|
||||
'dialplan show globals', 'dialplan set global' and 'dialplan set chanvar'
|
||||
instead.
|
||||
|
||||
* In the dialplan expression parser, the logical value of spaces
|
||||
immediately preceding a standalone 0 previously evaluated to
|
||||
true. It now evaluates to false. This has confused a good many
|
||||
people in the past (typically because they failed to realize the
|
||||
space had any significance). Since this violates the Principle of
|
||||
Least Surprise, it has been changed.
|
||||
|
||||
* While app_directory has always relied on having a voicemail.conf or users.conf file
|
||||
correctly set up, it now is dependent on app_voicemail being compiled as well.
|
||||
|
||||
* SIP: All of the functionality in SIPCHANINFO() has been implemented in CHANNEL(),
|
||||
and you should start using that function instead for retrieving information about
|
||||
the channel in a technology-agnostic way.
|
||||
|
||||
* If you have any third party modules which use a config file variable whose
|
||||
name ends in a '+', please note that the append capability added to this
|
||||
version may now conflict with that variable naming scheme. An easy
|
||||
workaround is to ensure that a space occurs between the '+' and the '=',
|
||||
to differentiate your variable from the append operator. This potential
|
||||
conflict is unlikely, but is documented here to be thorough.
|
||||
|
||||
* The "Join" event from app_queue now uses the CallerIDNum header instead of
|
||||
the CallerID header to indicate the CallerID number.
|
||||
|
||||
* If you use ODBC storage for voicemail, there is a new field called "flag"
|
||||
which should be a char(8) or larger. This field specifies whether or not a
|
||||
message has been designated to be "Urgent", "PRIORITY", or not.
|
|
@ -1,92 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
===
|
||||
===========================================================
|
||||
|
||||
From 10.4 to 10.5:
|
||||
|
||||
* The complex processor detection and optimization has been removed from
|
||||
the makefile in favor of using native optimization suppport when available.
|
||||
BUILD_NATIVE can be disabled via menuselect under "Compiler Flags".
|
||||
|
||||
From 10.2 to 10.3:
|
||||
|
||||
* If no transport is specified in sip.conf, transport will default to UDP.
|
||||
Also, if multiple transport= lines are used, only the last will be used.
|
||||
|
||||
From 1.8 to 10:
|
||||
|
||||
cel_pgsql:
|
||||
- This module now expects an 'extra' column in the database for data added
|
||||
using the CELGenUserEvent() application.
|
||||
|
||||
ConfBridge
|
||||
- ConfBridge's dialplan arguments have changed and are not
|
||||
backwards compatible.
|
||||
|
||||
File Interpreters
|
||||
- The format interpreter formats/format_sln16.c for the file extension
|
||||
'.sln16' has been removed. The '.sln16' file interpreter now exists
|
||||
in the formats/format_sln.c module along with new support for sln12,
|
||||
sln24, sln32, sln44, sln48, sln96, and sln192 file extensions.
|
||||
|
||||
HTTP:
|
||||
- A bindaddr must be specified in order for the HTTP server
|
||||
to run. Previous versions would default to 0.0.0.0 if no
|
||||
bindaddr was specified.
|
||||
|
||||
Gtalk:
|
||||
- The default value for 'context' and 'parkinglots' in gtalk.conf has
|
||||
been changed to 'default', previously they were empty.
|
||||
|
||||
chan_dahdi:
|
||||
- The mohinterpret=passthrough setting is deprecated in favor of
|
||||
moh_signaling=notify.
|
||||
|
||||
pbx_lua:
|
||||
- Execution no longer continues after applications that do dialplan jumps
|
||||
(such as app.goto). Now when an application such as app.goto() is called,
|
||||
control is returned back to the pbx engine and the current extension
|
||||
function stops executing.
|
||||
- the autoservice now defaults to being on by default
|
||||
- autoservice_start() and autoservice_start() no longer return a value.
|
||||
|
||||
Queue:
|
||||
- Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
|
||||
- QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
|
||||
|
||||
Asterisk Database:
|
||||
- The internal Asterisk database has been switched from Berkeley DB 1.86 to
|
||||
SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
|
||||
utility in the UTILS section of menuselect. If an existing astdb is found and no
|
||||
astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
|
||||
convert an existing astdb to the SQLite3 version automatically at runtime.
|
||||
|
||||
Module Support Level
|
||||
- All modules in the addons, apps, bridge, cdr, cel, channels, codecs,
|
||||
formats, funcs, pbx, and res have been updated to include MODULEINFO data
|
||||
that includes <support_level> tags with a value of core, extended, or deprecated.
|
||||
More information is available on the Asterisk wiki at
|
||||
https://wiki.asterisk.org/wiki/display/AST/Asterisk+Module+Support+States
|
||||
|
||||
Deprecated modules are now marked to not build by default and must be explicitly
|
||||
enabled in menuselect.
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
280
UPGRADE-11.txt
280
UPGRADE-11.txt
|
@ -1,280 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
|
||||
===
|
||||
===========================================================
|
||||
|
||||
From 11.6 to 11.7:
|
||||
ConfBridge
|
||||
- ConfBridge now has the ability to set the language of announcements to the
|
||||
conference. The language can be set on a bridge profile in confbridge.conf
|
||||
or by the dialplan function CONFBRIDGE(bridge,language)=en.
|
||||
chan_sip - Clarify The "sip show peers" Forcerport Column And Add Comedia
|
||||
- Under the "Forcerport" column, the "N" used to mean NAT (i.e. Yes). With
|
||||
the additon of auto_* NAT settings, the meaning changed and there was a
|
||||
certain combination of letters added to indicate the current setting. The
|
||||
combination of using "Y", "N", "A" or "a", can be confusing. Therefore, we
|
||||
now display clearly what the current Forcerport setting is: "Yes", "No",
|
||||
"Auto (Yes)", "Auto (No)".
|
||||
- Since we are clarifying the Forcerport column, we have added a column to
|
||||
display the Comedia setting since this is useful information as well. We
|
||||
no longer have a simple "NAT" setting like other versions before 11.
|
||||
|
||||
From 11.5 to 11.6:
|
||||
* res_agi will now properly indicate if there was an error in streaming an
|
||||
audio file. The result code will be -1 and the result returned from the
|
||||
the function will be RESULT_FAILURE instead of the prior behavior of always
|
||||
returning RESULT_SUCCESS even if there was an error.
|
||||
|
||||
From 11.4 to 11.5:
|
||||
* The default settings for chan_sip are now overriden properly by the general
|
||||
settings in sip.conf. Please look over your settings upon upgrading.
|
||||
|
||||
From 11.3 to 11.4:
|
||||
* Added the 'n' option to MeetMe to prevent application of the DENOISE function
|
||||
to a channel joining a conference. Some channel drivers that vary the number
|
||||
of audio samples in a voice frame will experience significant quality problems
|
||||
if a denoiser is attached to the channel; this option gives them the ability
|
||||
to remove the denoiser without having to unload func_speex.
|
||||
|
||||
* The Registry AMI event for SIP registrations will now always include the
|
||||
Username field. A previous bug fix missed an instance where it was not
|
||||
included; that has been corrected in this release.
|
||||
|
||||
From 11.2.0 to 11.2.1:
|
||||
* Asterisk would previously not output certain error messages when a remote
|
||||
console attempted to connect to Asterisk and no instance of Asterisk was
|
||||
running. This error message is displayed on stderr; as a result, some
|
||||
initialization scripts that used remote consoles to test for the presence
|
||||
of a running Asterisk instance started to display erroneous error messages.
|
||||
The init.d scripts and the safe_asterisk have been updated in the contrib
|
||||
folder to account for this.
|
||||
|
||||
From 11.2 to 11.3:
|
||||
|
||||
* Now by default, when Asterisk is installed in a path other than /usr, the
|
||||
Asterisk binary will search for shared libraries in ${libdir} in addition to
|
||||
searching system libraries. This allows Asterisk to find its shared
|
||||
libraries without having to specify LD_LIBRARY_PATH. This can be disabled by
|
||||
passing --disable-rpath to configure.
|
||||
|
||||
From 10 to 11:
|
||||
|
||||
Voicemail:
|
||||
- All voicemails now have a "msg_id" which uniquely identifies a message. For
|
||||
users of filesystem and IMAP storage of voicemail, this should be transparent.
|
||||
For users of ODBC, you will need to add a "msg_id" column to your voice mail
|
||||
messages table. This should be a string capable of holding at least 32 characters.
|
||||
All messages created in old Asterisk installations will have a msg_id added to
|
||||
them when required. This operation should be transparent as well.
|
||||
|
||||
Parking:
|
||||
- The comebacktoorigin setting must now be set per parking lot. The setting in
|
||||
the general section will not be applied automatically to each parking lot.
|
||||
- The BLINDTRANSFER channel variable is deleted from a channel when it is
|
||||
bridged to prevent subtle bugs in the parking feature. The channel
|
||||
variable is used by Asterisk internally for the Park application to work
|
||||
properly. If you were using it for your own purposes, copy it to your
|
||||
own channel variable before the channel is bridged.
|
||||
|
||||
res_ais:
|
||||
- Users of res_ais in versions of Asterisk prior to Asterisk 11 must change
|
||||
to use the res_corosync module, instead. OpenAIS is deprecated, but
|
||||
Corosync is still actively developed and maintained. Corosync came out of
|
||||
the OpenAIS project.
|
||||
|
||||
Dialplan Functions:
|
||||
- MAILBOX_EXISTS has been deprecated. Use VM_INFO with the 'exists' parameter
|
||||
instead.
|
||||
- Macro has been deprecated in favor of GoSub. For redirecting and connected
|
||||
line purposes use the following variables instead of their macro equivalents:
|
||||
REDIRECTING_SEND_SUB, REDIRECTING_SEND_SUB_ARGS,
|
||||
CONNECTED_LINE_SEND_SUB, CONNECTED_LINE_SEND_SUB_ARGS.
|
||||
- The REDIRECTING function now supports the redirecting original party id
|
||||
and reason.
|
||||
- The HANGUPCAUSE and HANGUPCAUSE_KEYS functions have been introduced to
|
||||
provide a replacement for the SIP_CAUSE hash. The HangupCauseClear
|
||||
application has also been introduced to remove this data from the channel
|
||||
when necessary.
|
||||
|
||||
|
||||
func_enum:
|
||||
- ENUM query functions now return a count of -1 on lookup error to
|
||||
differentiate between a failed query and a successful query with 0 results
|
||||
matching the specified type.
|
||||
|
||||
CDR:
|
||||
- cdr_adaptive_odbc now supports specifying a schema so that Asterisk can
|
||||
connect to databases that use schemas.
|
||||
|
||||
Configuration Files:
|
||||
- Files listed below have been updated to be more consistent with how Asterisk
|
||||
parses configuration files. This makes configuration files more consistent
|
||||
with what is expected across modules.
|
||||
|
||||
- cdr.conf: [general] and [csv] sections
|
||||
- dnsmgr.conf
|
||||
- dsp.conf
|
||||
|
||||
- The 'verbose' setting in logger.conf now takes an optional argument,
|
||||
specifying the verbosity level for each logging destination. The default,
|
||||
if not otherwise specified, is a verbosity of 3.
|
||||
|
||||
AMI:
|
||||
- DBDelTree now correctly returns an error when 0 rows are deleted just as
|
||||
the DBDel action does.
|
||||
- The IAX2 PeerStatus event now sends a 'Port' header. In Asterisk 10, this was
|
||||
erroneously being sent as a 'Post' header.
|
||||
|
||||
CCSS:
|
||||
- Macro is deprecated. Use cc_callback_sub instead of cc_callback_macro
|
||||
in channel configurations.
|
||||
|
||||
app_meetme:
|
||||
- The 'c' option (announce user count) will now work even if the 'q' (quiet)
|
||||
option is enabled.
|
||||
|
||||
app_followme:
|
||||
- Answered outgoing calls no longer get cut off when the next step is started.
|
||||
You now have until the last step times out to decide if you want to accept
|
||||
the call or not before being disconnected.
|
||||
|
||||
chan_gtalk:
|
||||
- chan_gtalk has been deprecated in favor of the chan_motif channel driver. It is recommended
|
||||
that users switch to using it as it is a core supported module.
|
||||
|
||||
chan_jingle:
|
||||
- chan_jingle has been deprecated in favor of the chan_motif channel driver. It is recommended
|
||||
that users switch to using it as it is a core supported module.
|
||||
|
||||
SIP
|
||||
===
|
||||
- A new option "tonezone" for setting default tonezone for the channel driver
|
||||
or individual devices
|
||||
- A new manager event, "SessionTimeout" has been added and is triggered when
|
||||
a call is terminated due to RTP stream inactivity or SIP session timer
|
||||
expiration.
|
||||
- SIP_CAUSE is now deprecated. It has been modified to use the same
|
||||
mechanism as the HANGUPCAUSE function. Behavior should not change, but
|
||||
performance should be vastly improved. The HANGUPCAUSE function should now
|
||||
be used instead of SIP_CAUSE. Because of this, the storesipcause option in
|
||||
sip.conf is also deprecated.
|
||||
- The sip paramater for Originating Line Information (oli, isup-oli, and
|
||||
ss7-oli) is now parsed out of the From header and copied into the channel's
|
||||
ANI2 information field. This is readable from the CALLERID(ani2) dialplan
|
||||
function.
|
||||
- ICE support has been added and is enabled by default. Some endpoints may have
|
||||
problems with the ICE candidates within the SDP. If this is the case ICE support
|
||||
can be disabled globally or on a per-endpoint basis using the icesupport
|
||||
configuration option. Symptoms of this include one way media or no media flow.
|
||||
|
||||
chan_unistim
|
||||
- Due to massive update in chan_unistim phone keys functions and on-screen
|
||||
information changed.
|
||||
|
||||
users.conf:
|
||||
- A defined user with hasvoicemail=yes now finally uses a Gosub to stdexten
|
||||
as documented in extensions.conf.sample since v1.6.0 instead of a Macro as
|
||||
documented in v1.4. Set the asterisk.conf stdexten=macro parameter to
|
||||
invoke the stdexten the old way.
|
||||
|
||||
res_jabber
|
||||
- This module has been deprecated in favor of the res_xmpp module. The res_xmpp
|
||||
module is backwards compatible with the res_jabber configuration file, dialplan
|
||||
functions, and AMI actions. The old CLI commands can also be made available using
|
||||
the res_clialiases template for Asterisk 11.
|
||||
|
||||
From 1.8 to 10:
|
||||
|
||||
cel_pgsql:
|
||||
- This module now expects an 'extra' column in the database for data added
|
||||
using the CELGenUserEvent() application.
|
||||
|
||||
ConfBridge
|
||||
- ConfBridge's dialplan arguments have changed and are not
|
||||
backwards compatible.
|
||||
|
||||
File Interpreters
|
||||
- The format interpreter formats/format_sln16.c for the file extension
|
||||
'.sln16' has been removed. The '.sln16' file interpreter now exists
|
||||
in the formats/format_sln.c module along with new support for sln12,
|
||||
sln24, sln32, sln44, sln48, sln96, and sln192 file extensions.
|
||||
|
||||
HTTP:
|
||||
- A bindaddr must be specified in order for the HTTP server
|
||||
to run. Previous versions would default to 0.0.0.0 if no
|
||||
bindaddr was specified.
|
||||
|
||||
Gtalk:
|
||||
- The default value for 'context' and 'parkinglots' in gtalk.conf has
|
||||
been changed to 'default', previously they were empty.
|
||||
|
||||
chan_dahdi:
|
||||
- The mohinterpret=passthrough setting is deprecated in favor of
|
||||
moh_signaling=notify.
|
||||
|
||||
pbx_lua:
|
||||
- Execution no longer continues after applications that do dialplan jumps
|
||||
(such as app.goto). Now when an application such as app.goto() is called,
|
||||
control is returned back to the pbx engine and the current extension
|
||||
function stops executing.
|
||||
- the autoservice now defaults to being on by default
|
||||
- autoservice_start() and autoservice_start() no longer return a value.
|
||||
|
||||
Queue:
|
||||
- Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
|
||||
- QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
|
||||
|
||||
Asterisk Database:
|
||||
- The internal Asterisk database has been switched from Berkeley DB 1.86 to
|
||||
SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
|
||||
utility in the UTILS section of menuselect. If an existing astdb is found and no
|
||||
astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
|
||||
convert an existing astdb to the SQLite3 version automatically at runtime. If
|
||||
moving back from Asterisk 10 to Asterisk 1.8, the astdb2bdb utility can be used
|
||||
to create a Berkeley DB copy of the SQLite3 astdb that Asterisk 10 uses.
|
||||
|
||||
Manager:
|
||||
- The AMI protocol version was incremented to 1.2 as a result of changing two
|
||||
instances of the Unlink event to Bridge events. This change was documented
|
||||
as part of the AMI 1.1 update, but two Unlink events were inadvertently left
|
||||
unchanged.
|
||||
|
||||
Module Support Level
|
||||
- All modules in the addons, apps, bridge, cdr, cel, channels, codecs,
|
||||
formats, funcs, pbx, and res have been updated to include MODULEINFO data
|
||||
that includes <support_level> tags with a value of core, extended, or deprecated.
|
||||
More information is available on the Asterisk wiki at
|
||||
https://wiki.asterisk.org/wiki/display/AST/Asterisk+Module+Support+States
|
||||
|
||||
Deprecated modules are now marked to not build by default and must be explicitly
|
||||
enabled in menuselect.
|
||||
|
||||
chan_sip:
|
||||
- Setting of HASH(SIP_CAUSE,<slave-channel-name>) on channels is now disabled
|
||||
by default. It can be enabled using the 'storesipcause' option. This feature
|
||||
has a significant performance penalty.
|
||||
|
||||
UDPTL:
|
||||
- The default UDPTL port range in udptl.conf.sample differed from the defaults
|
||||
in the source. If you didn't have a config file, you got 4500 to 4599. Now the
|
||||
default is 4000 to 4999.
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
478
UPGRADE-12.txt
478
UPGRADE-12.txt
|
@ -1,478 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
|
||||
=== UPGRADE-11.txt -- Upgrade info for 10 to 11
|
||||
===
|
||||
===========================================================
|
||||
|
||||
There are many significant architectural changes in Asterisk 12. It is
|
||||
recommended that you not only read through this document for important
|
||||
changes that affect an upgrade, but that you also read through the CHANGES
|
||||
document in depth to better understand the new options available to you.
|
||||
|
||||
Additional information on the architectural changes made in Asterisk can be
|
||||
found on the Asterisk wiki (https://wiki.asterisk.org)
|
||||
|
||||
Of particular note, the following systems in Asterisk underwent significant
|
||||
changes. Documentation for the changes and a specification for their
|
||||
behavior in Asterisk 12 is also available on the Asterisk wiki.
|
||||
- AMI: Many events were changed, and the semantics of channels and bridges
|
||||
were defined. In particular, how channels and bridges behave under
|
||||
transfer scenarios and situations involving multiple parties has
|
||||
changed significantly. See https://wiki.asterisk.org/wiki/x/dAFRAQ
|
||||
for more information.
|
||||
- CDR: CDR logic was extracted from the many locations it existed in across
|
||||
Asterisk and implemented as a consumer of Stasis message bus events.
|
||||
As a result, consistency of records has improved significantly and the
|
||||
behavior of CDRs in transfer scenarios has been defined in the CDR
|
||||
specification. However, significant behavioral changes in CDRs resulted
|
||||
from the transition. The most significant change is the addition of
|
||||
CDR entries when a channel who is the Party A in a CDR leaves a bridge.
|
||||
See https://wiki.asterisk.org/wiki/x/pwpRAQ for more information.
|
||||
- CEL: Much like CDRs, CEL was removed from the many locations it existed in
|
||||
across Asterisk and implemented as a consumer of Stasis message bus
|
||||
events. It now closely follows the Bridging API model of channels and
|
||||
bridges, and has a much closer consistency of conveyed events as AMI.
|
||||
For the changes in events, see https://wiki.asterisk.org/wiki/x/4ICLAQ.
|
||||
|
||||
Build System:
|
||||
- Removed the CHANNEL_TRACE development mode build option. Certain aspects of
|
||||
the CHANNEL_TRACE build option were incompatible with the new bridging
|
||||
architecture.
|
||||
|
||||
- Asterisk now depends on libjansson, libuuid and optionally (but recommended)
|
||||
libxslt and uriparser.
|
||||
|
||||
- The new SIP stack and channel driver uses a particular version of PJSIP.
|
||||
Please see https://wiki.asterisk.org/wiki/x/J4GLAQ for more information on
|
||||
configuring and installing PJSIP for use with Asterisk.
|
||||
|
||||
AgentLogin and chan_agent:
|
||||
- Along with AgentRequest, this application has been modified to be a
|
||||
replacement for chan_agent. The chan_agent module and the Agent channel
|
||||
driver have been removed from Asterisk, as the concept of a channel driver
|
||||
proxying in front of another channel driver was incompatible with the new
|
||||
architecture (and has had numerous problems through past versions of
|
||||
Asterisk). The act of a channel calling the AgentLogin application places the
|
||||
channel into a pool of agents that can be requested by the AgentRequest
|
||||
application. Note that this application, as well as all other agent related
|
||||
functionality, is now provided by the app_agent_pool module.
|
||||
|
||||
- This application no longer performs agent authentication. If authentication
|
||||
is desired, the dialplan needs to perform this function using the
|
||||
Authenticate or VMAuthenticate application or through an AGI script before
|
||||
running AgentLogin.
|
||||
|
||||
- The agents.conf schema has changed. Rather than specifying agents on a
|
||||
single line in comma delineated fashion, each agent is defined in a separate
|
||||
context. This allows agents to use the power of context templates in their
|
||||
definition.
|
||||
|
||||
- A number of parameters from agents.conf have been removed. This includes
|
||||
maxloginretries, autologoffunavail, updatecdr, goodbye, group, recordformat,
|
||||
urlprefix, and savecallsin. These options were obsoleted by the move from
|
||||
a channel driver model to the bridging/application model provided by
|
||||
app_agent_pool.
|
||||
|
||||
- The AGENTUPDATECDR channel variable has also been removed, for the same
|
||||
reason as the updatecdr option.
|
||||
|
||||
- The endcall and enddtmf configuration options are removed. Use the
|
||||
dialplan function CHANNEL(dtmf_features) to set DTMF features on the agent
|
||||
channel before calling AgentLogin.
|
||||
|
||||
AgentMonitorOutgoing
|
||||
- This application has been removed. It was a holdover from when
|
||||
AgentCallbackLogin was removed.
|
||||
|
||||
Answer
|
||||
- It is no longer possible to bypass updating the CDR when answering a
|
||||
channel. CDRs are based on the channel state and will be updated when
|
||||
the channel is Answered.
|
||||
|
||||
ControlPlayback
|
||||
- The channel variable CPLAYBACKSTATUS may now return the value
|
||||
'REMOTESTOPPED' when playback is stopped by an external entity.
|
||||
|
||||
DISA
|
||||
- This application now has a dependency on the app_cdr module. It uses this
|
||||
module to hide the CDR created prior to execution of the DISA application.
|
||||
|
||||
DumpChan:
|
||||
- The output of DumpChan no longer includes the DirectBridge or IndirectBridge
|
||||
fields. Instead, if a channel is in a bridge, it includes a BridgeID field
|
||||
containing the unique ID of the bridge that the channel happens to be in.
|
||||
|
||||
ForkCDR:
|
||||
- Nearly every parameter in ForkCDR has been updated and changed to reflect
|
||||
the changes in CDRs. Please see the documentation for the ForkCDR
|
||||
application, as well as the CDR specification on the Asterisk wiki.
|
||||
|
||||
NoCDR:
|
||||
- The NoCDR application has been deprecated. Please use the CDR_PROP function
|
||||
to disable CDRs on a channel.
|
||||
|
||||
ParkAndAnnounce:
|
||||
- The app_parkandannounce module has been removed. The application
|
||||
ParkAndAnnounce is now provided by the res_parking module. See the
|
||||
Parking changes for more information.
|
||||
|
||||
ResetCDR:
|
||||
- The 'w' and 'a' options have been removed. Dispatching CDRs to registered
|
||||
backends occurs on an as-needed basis in order to preserve linkedid
|
||||
propagation and other needed behavior.
|
||||
- The 'e' option is deprecated. Please use the CDR_PROP function to enable
|
||||
CDRs on a channel that they were previously disabled on.
|
||||
- The ResetCDR application is no longer a part of core Asterisk, and instead
|
||||
is now delivered as part of app_cdr.
|
||||
|
||||
Queues:
|
||||
- Queue strategy rrmemory now has a predictable order similar to strategy
|
||||
rrordered. Members will be called in the order that they are added to the
|
||||
queue.
|
||||
|
||||
- Removed the queues.conf check_state_unknown option. It is no longer
|
||||
necessary.
|
||||
|
||||
- It is now possible to play the Queue prompts to the first user waiting in a
|
||||
call queue. Note that this may impact the ability for agents to talk with
|
||||
users, as a prompt may still be playing when an agent connects to the user.
|
||||
This ability is disabled by default but can be enabled on an individual
|
||||
queue using the 'announce-to-first-user' option.
|
||||
|
||||
- The configuration options eventwhencalled and eventmemberstatus have been
|
||||
removed. As a result, the AMI events QueueMemberStatus, AgentCalled,
|
||||
AgentConnect, AgentComplete, AgentDump, and AgentRingNoAnswer will always be
|
||||
sent. The "Variable" fields will also no longer exist on the Agent* events.
|
||||
These events can be filtered out from a connected AMI client using the
|
||||
eventfilter setting in manager.conf.
|
||||
|
||||
- The queue log now differentiates between blind and attended transfers. A
|
||||
blind transfer will result in a BLINDTRANSFER message with the destination
|
||||
context and extension. An attended transfer will result in an
|
||||
ATTENDEDTRANSFER message. This message will indicate the method by which
|
||||
the attended transfer was completed: "BRIDGE" for a bridge merge, "APP"
|
||||
for running an application on a bridge or channel, or "LINK" for linking
|
||||
two bridges together with local channels. The queue log will also now detect
|
||||
externally initiated blind and attended transfers and record the transfer
|
||||
status accordingly.
|
||||
|
||||
- When performing queue pause/unpause on an interface without specifying an
|
||||
individual queue, the PAUSEALL/UNPAUSEALL event will only be logged if at
|
||||
least one member of any queue exists for that interface.
|
||||
|
||||
SetAMAFlags
|
||||
- This application is deprecated in favor of CHANNEL(amaflags).
|
||||
|
||||
VoiceMail:
|
||||
- Mailboxes defined by app_voicemail MUST be referenced by the rest of the
|
||||
system as mailbox@context. The rest of the system cannot add @default
|
||||
to mailbox identifiers for app_voicemail that do not specify a context
|
||||
any longer. It is a mailbox identifier format that should only be
|
||||
interpreted by app_voicemail.
|
||||
|
||||
- The voicemail.conf configuration file now has an 'alias' configuration
|
||||
parameter for use with the Directory application. The voicemail realtime
|
||||
database table schema has also been updated with an 'alias' column. Systems
|
||||
using voicemail with realtime should update their schemas accordingly.
|
||||
|
||||
Channel Drivers:
|
||||
- When a channel driver is configured to enable jiterbuffers, they are now
|
||||
applied unconditionally when a channel joins a bridge. If a jitterbuffer
|
||||
is already set for that channel when it enters, such as by the JITTERBUFFER
|
||||
function, then the existing jitterbuffer will be used and the one set by
|
||||
the channel driver will not be applied.
|
||||
|
||||
chan_bridge
|
||||
- chan_bridge is removed and its functionality is incorporated into ConfBridge
|
||||
itself.
|
||||
|
||||
chan_dahdi:
|
||||
- Analog port dialing and deferred DTMF dialing for PRI now distinguishes
|
||||
between 'w' and 'W'. The 'w' pauses dialing for half a second. The 'W'
|
||||
pauses dialing for one second.
|
||||
|
||||
- The default for inband_on_proceeding has changed to no.
|
||||
|
||||
- The CLI command 'dahdi destroy channel' is now 'dahdi destroy channels'.
|
||||
A range of channels can be specified to be destroyed. Note that this command
|
||||
should only be used if you understand the risks it entails.
|
||||
|
||||
- The script specified by the chan_dahdi.conf mwimonitornotify option now gets
|
||||
the exact configured mailbox name. For app_voicemail mailboxes this is
|
||||
mailbox@context.
|
||||
|
||||
- Added mwi_vm_boxes that also must be configured for ISDN MWI to be enabled.
|
||||
|
||||
- ignore_failed_channels now defaults to True: the channel will continue to
|
||||
be configured even if configuring it has failed. This is generally a
|
||||
better setup for systems with not more than one DAHDI device or with DAHDI
|
||||
>= 2.8.0 .
|
||||
|
||||
chan_local:
|
||||
- The /b option has been removed.
|
||||
|
||||
- chan_local moved into the system core and is no longer a loadable module.
|
||||
|
||||
chan_sip:
|
||||
- The 'callevents' parameter has been removed. Hold AMI events are now raised
|
||||
in the core, and can be filtered out using the 'eventfilter' parameter
|
||||
in manager.conf.
|
||||
|
||||
- Dynamic realtime tables for SIP Users can now include a 'path' field. This
|
||||
will store the path information for that peer when it registers. Realtime
|
||||
tables can also use the 'supportpath' field to enable Path header support.
|
||||
|
||||
- LDAP realtime configurations for SIP Users now have the AstAccountPathSupport
|
||||
objectIdentifier. This maps to the supportpath option in sip.conf.
|
||||
|
||||
Core:
|
||||
- Masquerades as an operation inside Asterisk have been effectively hidden
|
||||
by the migration to the Bridging API. As such, many 'quirks' of Asterisk
|
||||
no longer occur. This includes renaming of channels, "<ZOMBIE>" channels,
|
||||
dropping of frame/audio hooks, and other internal implementation details
|
||||
that users had to deal with. This fundamental change has large implications
|
||||
throughout the changes documented for this version. For more information
|
||||
about the new core architecture of Asterisk, please see the Asterisk wiki.
|
||||
|
||||
- The following channel variables have changed behavior which is described in
|
||||
the CHANGES file: TRANSFER_CONTEXT, BRIDGEPEER, BRIDGEPVTCALLID,
|
||||
ATTENDED_TRANSFER_COMPLETE_SOUND, DYNAMIC_FEATURENAME, and DYNAMIC_PEERNAME.
|
||||
|
||||
AMI (Asterisk Manager Interface):
|
||||
- Version 1.4 - The details of what happens to a channel when a masquerade
|
||||
happens (transfers, parking, etc) have changed.
|
||||
- The Masquerade event now includes the Uniqueid's of the clone and original
|
||||
channels.
|
||||
- Channels no longer swap Uniqueid's as a result of the masquerade.
|
||||
- Instead of a shell game of renames, there's now a single rename, appending
|
||||
<ZOMBIE> to the name of the original channel.
|
||||
|
||||
- *Major* changes were made to both the syntax as well as the semantics of the
|
||||
AMI protocol. In particular, AMI events have been substantially modified
|
||||
and improved in this version of Asterisk. The major event changes are listed
|
||||
below.
|
||||
- NewPeerAccount has been removed. NewAccountCode is raised instead.
|
||||
- Reload events have been consolidated and standardized.
|
||||
- ModuleLoadReport has been removed.
|
||||
- FaxSent is now SendFAX; FaxReceived is now ReceiveFAX. This standardizes
|
||||
app_fax and res_fax events.
|
||||
- MusicOnHold has been replaced with MusicOnHoldStart and MusicOnHoldStop.
|
||||
- JabberEvent has been removed.
|
||||
- Hold is now in the core and will now raise Hold and Unhold events.
|
||||
- Join is now QueueCallerJoin.
|
||||
- Leave is now QueueCallerLeave.
|
||||
- Agentlogin/Agentlogoff is now AgentLogin/AgentLogoff, respectively.
|
||||
- ChannelUpdate has been removed.
|
||||
- Local channel optimization is now conveyed via LocalOptimizationBegin and
|
||||
LocalOptimizationEnd.
|
||||
- BridgeAction and BridgeExec have been removed.
|
||||
- BlindTransfer and AttendedTransfer events were added.
|
||||
- Dial is now DialBegin and DialEnd.
|
||||
- DTMF is now DTMFBegin and DTMFEnd.
|
||||
- Bridge has been replaced with BridgeCreate, BridgeEnter, BridgeLeave, and
|
||||
BridgeDestroy
|
||||
- MusicOnHold has been replaced with MusicOnHoldStart and MusicOnHoldStop
|
||||
- AGIExec is now AGIExecStart and AGIExecEnd
|
||||
- AsyncAGI is now AsyncAGIStart, AsyncAGIExec, and AsyncAGIEnd
|
||||
|
||||
- The 'MCID' AMI event now publishes a channel snapshot when available and
|
||||
its non-channel-snapshot parameters now use either the "MCallerID" or
|
||||
'MConnectedID' prefixes with Subaddr*, Name*, and Num* suffixes instead
|
||||
of 'CallerID' and 'ConnectedID' to avoid confusion with similarly named
|
||||
parameters in the channel snapshot.
|
||||
|
||||
- The 'Channel' key used in the 'AlarmClear', 'Alarm', and 'DNDState' has been
|
||||
renamed "DAHDIChannel" since it does not convey an Asterisk channel name.
|
||||
|
||||
- All AMI events now contain a 'SystemName' field, if available.
|
||||
|
||||
- Local channel information in events is now prefixed with 'LocalOne' and
|
||||
'LocalTwo'. This replaces the suffix of '1' and '2' for the two halves of
|
||||
the Local channel. This affects the 'LocalBridge', 'LocalOptimizationBegin',
|
||||
and 'LocalOptimizationEnd' events.
|
||||
|
||||
- The 'RTCPSent'/'RTCPReceived' events have been significantly modified from
|
||||
previous versions. They now report all SR/RR packets sent/received, and
|
||||
have been restructured to better reflect the data sent in a SR/RR. In
|
||||
particular, the event structure now supports multiple report blocks.
|
||||
|
||||
- The deprecated use of | (pipe) as a separator in the channelvars setting in
|
||||
manager.conf has been removed.
|
||||
|
||||
- The SIP SIPqualifypeer action now sends a response indicating it will qualify
|
||||
a peer once a peer has been found to qualify. Once the qualify has been
|
||||
completed it will now issue a SIPqualifypeerdone event.
|
||||
|
||||
- The AMI event 'Newexten' field 'Extension' is deprecated, and may be removed
|
||||
in a future release. Please use the common 'Exten' field instead.
|
||||
|
||||
- The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
|
||||
'UnParkedCall' have changed significantly in the new res_parking module.
|
||||
- The 'Channel' and 'From' headers are gone. For the channel that was parked
|
||||
or is coming out of parking, a 'Parkee' channel snapshot is issued and it
|
||||
has a number of fields associated with it. The old 'Channel' header relayed
|
||||
the same data as the new 'ParkeeChannel' header.
|
||||
- The 'From' field was ambiguous and changed meaning depending on the event.
|
||||
for most of these, it was the name of the channel that parked the call
|
||||
(the 'Parker'). There is no longer a header that provides this channel name,
|
||||
however the 'ParkerDialString' will contain a dialstring to redial the
|
||||
device that parked the call.
|
||||
- On UnParkedCall events, the 'From' header would instead represent the
|
||||
channel responsible for retrieving the parkee. It receives a channel
|
||||
snapshot labeled 'Retriever'. The 'from' field is is replaced with
|
||||
'RetrieverChannel'.
|
||||
- Lastly, the 'Exten' field has been replaced with 'ParkingSpace'.
|
||||
|
||||
- The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar
|
||||
fashion has changed the field names 'StartExten' and 'StopExten' to
|
||||
'StartSpace' and 'StopSpace' respectively.
|
||||
|
||||
- The AMI 'Status' response event to the AMI Status action replaces the
|
||||
'BridgedChannel' and 'BridgedUniqueid' headers with the 'BridgeID' header to
|
||||
indicate what bridge the channel is currently in.
|
||||
|
||||
CDR (Call Detail Records)
|
||||
- Significant changes have been made to the behavior of CDRs. The CDR engine
|
||||
was effectively rewritten and built on the Stasis message bus. For a full
|
||||
definition of CDR behavior in Asterisk 12, please read the specification
|
||||
on the Asterisk wiki (wiki.asterisk.org).
|
||||
|
||||
- CDRs will now be created between all participants in a bridge. For each
|
||||
pair of channels in a bridge, a CDR is created to represent the path of
|
||||
communication between those two endpoints. This lets an end user choose who
|
||||
to bill for what during bridge operations with multiple parties.
|
||||
|
||||
- The duration, billsec, start, answer, and end times now reflect the times
|
||||
associated with the current CDR for the channel, as opposed to a cumulative
|
||||
measurement of all CDRs for that channel.
|
||||
|
||||
CEL:
|
||||
- The Uniqueid field for a channel is now a stable identifier, and will not
|
||||
change due to transfers, parking, etc.
|
||||
|
||||
- CEL has undergone significant rework in Asterisk 12, and is now built on the
|
||||
Stasis message bus. Please see the specification for CEL on the Asterisk
|
||||
wiki at https://wiki.asterisk.org/wiki/x/4ICLAQ for more detailed
|
||||
information. A summary of the affected events is below:
|
||||
- BRIDGE_START, BRIDGE_END, BRIDGE_UPDATE, 3WAY_START, 3WAY_END, CONF_ENTER,
|
||||
CONF_EXIT, CONF_START, and CONF_END events have all been removed. These
|
||||
events have been replaced by BRIDGE_ENTER/BRIDGE_EXIT.
|
||||
- BLINDTRANSFER/ATTENDEDTRANSFER events now report the peer as NULL and
|
||||
additional information in the extra string field.
|
||||
|
||||
Dialplan Functions:
|
||||
|
||||
- Certain dialplan functions have been marked as 'dangerous', and may only be
|
||||
executed from the dialplan. Execution from extenal sources (AMI's GetVar and
|
||||
SetVar actions; etc.) may be inhibited by setting live_dangerously in the
|
||||
[options] section of asterisk.conf to no. SHELL(), channel locking, and
|
||||
direct file read/write functions are marked as dangerous. DB_DELETE() and
|
||||
REALTIME_DESTROY() are marked as dangerous for reads, but can now safely
|
||||
accept writes (which ignore the provided value).
|
||||
- The default value for live_dangerously was changed from yes (in Asterisk 11
|
||||
and earlier) to no (in Asterisk 12 and greater).
|
||||
|
||||
Dialplan:
|
||||
- All channel and global variable names are evaluated in a case-sensitive
|
||||
manner. In previous versions of Asterisk, variables created and evaluated in
|
||||
the dialplan were evaluated case-insensitively, but built-in variables and
|
||||
variable evaluation done internally within Asterisk was done
|
||||
case-sensitively.
|
||||
|
||||
- Asterisk has always had code to ignore dash '-' characters that are not
|
||||
part of a character set in the dialplan extensions. The code now
|
||||
consistently ignores these characters when matching dialplan extensions.
|
||||
|
||||
- BRIDGE_FEATURES channel variable is now casesensitive for feature letter
|
||||
codes. Uppercase variants apply them to the calling party while lowercase
|
||||
variants apply them to the called party.
|
||||
|
||||
Features:
|
||||
- The features.conf [applicationmap] <FeatureName> ActivatedBy option is
|
||||
no longer honored. The feature is always activated by the channel that has
|
||||
DYNAMIC_FEATURES defined on it when it enters the bridge. Use predial to set
|
||||
different values of DYNAMIC_FEATURES on the channels
|
||||
|
||||
- Executing a dynamic feature on the bridge peer in a multi-party bridge will
|
||||
execute it on all peers of the activating channel.
|
||||
|
||||
- There is no longer an explicit 'features reload' CLI command. Features can
|
||||
still be reloaded using 'module reload features'.
|
||||
|
||||
- It is no longer necessary (or possible) to define the ATXFER_NULL_TECH in
|
||||
features.c for atxferdropcall=no to work properly. This option now just
|
||||
works.
|
||||
|
||||
Parking:
|
||||
- Parking has been extracted from the Asterisk core as a loadable module,
|
||||
res_parking.
|
||||
|
||||
- Configuration is found in res_parking.conf. It is no longer supported in
|
||||
features.conf
|
||||
|
||||
- The arguments for the Park, ParkedCall, and ParkAndAnnounce applications
|
||||
have been modified significantly. See the application documents for
|
||||
specific details.
|
||||
|
||||
- Numerous changes to Parking related applications, AMI and CLI commands and
|
||||
internal inter-workings have been made. Please read the CHANGES file for
|
||||
the detailed list.
|
||||
|
||||
Security Events Framework:
|
||||
- Security Event timestamps now use ISO 8601 formatted date/time instead of
|
||||
the "seconds-microseconds" format that it was using previously.
|
||||
|
||||
AGENT:
|
||||
- The password option has been disabled, as the AgentLogin application no
|
||||
longer provides authentication.
|
||||
|
||||
AUDIOHOOK_INHERIT:
|
||||
- Due to changes in the Asterisk core, this function is no longer needed to
|
||||
preserve a MixMonitor on a channel during transfer operations and dialplan
|
||||
execution. It is effectively obsolete.
|
||||
|
||||
CDR: (function)
|
||||
- The 'amaflags' and 'accountcode' attributes for the CDR function are
|
||||
deprecated. Use the CHANNEL function instead to access these attributes.
|
||||
|
||||
- The 'l' option has been removed. When reading a CDR attribute, the most
|
||||
recent record is always used. When writing a CDR attribute, all non-finalized
|
||||
CDRs are updated.
|
||||
|
||||
- The 'r' option has been removed, for the same reason as the 'l' option.
|
||||
|
||||
- The 's' option has been removed, as LOCKED semantics no longer exist in the
|
||||
CDR engine.
|
||||
|
||||
VMCOUNT:
|
||||
- Mailboxes defined by app_voicemail MUST be referenced by the rest of the
|
||||
system as mailbox@context. The rest of the system cannot add @default
|
||||
to mailbox identifiers for app_voicemail that do not specify a context
|
||||
any longer. It is a mailbox identifier format that should only be
|
||||
interpreted by app_voicemail.
|
||||
|
||||
res_rtp_asterisk:
|
||||
- ICE/STUN/TURN support in res_rtp_asterisk has been made optional. To enable
|
||||
them, an Asterisk-specific version of PJSIP needs to be installed.
|
||||
Tarballs are available from https://github.com/asterisk/pjproject/tags/.
|
||||
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
399
UPGRADE-13.txt
399
UPGRADE-13.txt
|
@ -1,399 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
|
||||
=== UPGRADE-11.txt -- Upgrade info for 10 to 11
|
||||
=== UPGRADE-12.txt -- Upgrade info for 11 to 12
|
||||
===========================================================
|
||||
|
||||
General Asterisk Changes:
|
||||
- The asterisk command line -I option and the asterisk.conf internal_timing
|
||||
option are removed and always enabled if any timing module is loaded.
|
||||
|
||||
- The per console verbose level feature as previously implemented caused a
|
||||
large performance penalty. The fix required some minor incompatibilities
|
||||
if the new rasterisk is used to connect to an earlier version. If the new
|
||||
rasterisk connects to an older Asterisk version then the root console verbose
|
||||
level is always affected by the "core set verbose" command of the remote
|
||||
console even though it may appear to only affect the current console. If
|
||||
an older version of rasterisk connects to the new version then the
|
||||
"core set verbose" command will have no effect.
|
||||
|
||||
- The asterisk compatibility options in asterisk.conf have been removed.
|
||||
These options enabled certain backwards compatibility features for
|
||||
pbx_realtime, res_agi, and app_set that made their behaviour similar to
|
||||
Asterisk 1.4. Users who used these backwards compatibility settings should
|
||||
update their dialplans to use ',' instead of '|' as a delimiter, and should
|
||||
use the Set dialplan application instead of the MSet dialplan application.
|
||||
|
||||
Build System:
|
||||
- Sample config files have been moved from configs/ to a subfolder of that
|
||||
directory, 'samples'.
|
||||
|
||||
- The menuselect utility has been pulled into the Asterisk repository. As a
|
||||
result, the libxml2 development library is now a required dependency for
|
||||
Asterisk.
|
||||
|
||||
- Added a new Compiler Flag, REF_DEBUG. When enabled, reference counted
|
||||
objects will emit additional debug information to the refs log file located
|
||||
in the standard Asterisk log file directory. This log file is useful in
|
||||
tracking down object leaks and other reference counting issues. Prior to
|
||||
this version, this option was only available by modifying the source code
|
||||
directly. This change also includes a new script, refcounter.py, in the
|
||||
contrib folder that will process the refs log file.
|
||||
|
||||
Applications:
|
||||
|
||||
ConfBridge:
|
||||
- The sound_place_into_conference sound used in Confbridge is now deprecated
|
||||
and is no longer functional since it has been broken since its inception
|
||||
and the fix involved using a different method to achieve the same goal. The
|
||||
new method to achieve this functionality is by using sound_begin to play
|
||||
a sound to the conference when waitmarked users are moved into the conference.
|
||||
|
||||
- Added 'Admin' header to ConfbridgeJoin, ConfbridgeLeave, ConfbridgeMute,
|
||||
ConfbridgeUnmute, and ConfbridgeTalking AMI events.
|
||||
|
||||
ControlPlayback:
|
||||
- The ControlPlayback and 'control stream file' AGI command will no longer
|
||||
implicitly answer the channel. If you do not answer the channel prior to
|
||||
using either this application or AGI command, you must send Progress
|
||||
first.
|
||||
|
||||
Queue:
|
||||
- Queue rules provided in queuerules.conf can no longer be named "general".
|
||||
|
||||
SetMusicOnHold:
|
||||
- The SetMusicOnHold dialplan application was deprecated and has been removed.
|
||||
Users of the application should use the CHANNEL function's musicclass
|
||||
setting instead.
|
||||
|
||||
WaitMusicOnHold:
|
||||
- The WaitMusicOnHold dialplan application was deprecated and has been
|
||||
removed. Users of the application should use MusicOnHold with a duration
|
||||
parameter instead.
|
||||
|
||||
CDR Backends:
|
||||
- The cdr_sqlite module was deprecated and has been removed. Users of this
|
||||
module should use the cdr_sqlite3_custom module instead.
|
||||
|
||||
Channel Drivers:
|
||||
|
||||
chan_dahdi:
|
||||
- SS7 support now requires libss7 v2.0 or later.
|
||||
|
||||
- Added the inband_on_setup_ack compatibility option to chan_dahdi.conf to
|
||||
deal with switches that don't send an inband progress indication in the
|
||||
SETUP ACKNOWLEDGE message.
|
||||
Default is now no.
|
||||
|
||||
chan_gtalk
|
||||
- This module was deprecated and has been removed. Users of chan_gtalk
|
||||
should use chan_motif.
|
||||
|
||||
chan_h323
|
||||
- This module was deprecated and has been removed. Users of chan_h323
|
||||
should use chan_ooh323.
|
||||
|
||||
chan_jingle
|
||||
- This module was deprecated and has been removed. Users of chan_jingle
|
||||
should use chan_motif.
|
||||
|
||||
chan_pjsip:
|
||||
- Added a 'force_avp' option to chan_pjsip which will force the usage of
|
||||
'RTP/AVP', 'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' as the media transport type
|
||||
in SDP offers depending on settings, even when DTLS is used for media
|
||||
encryption.
|
||||
|
||||
- Added a 'media_use_received_transport' option to chan_pjsip which will
|
||||
cause the SDP answer to use the media transport as received in the SDP
|
||||
offer.
|
||||
|
||||
chan_sip:
|
||||
- Made set SIPREFERREDBYHDR as inheritable for better chan_pjsip
|
||||
interoperability.
|
||||
|
||||
- The SIPPEER dialplan function no longer supports using a colon as a
|
||||
delimiter for parameters. The parameters for the function should be
|
||||
delimited using a comma.
|
||||
|
||||
- The SIPCHANINFO dialplan function was deprecated and has been removed. Users
|
||||
of the function should use the CHANNEL function instead.
|
||||
|
||||
- Added a 'force_avp' option for chan_sip. When enabled this option will
|
||||
cause the media transport in the offer or answer SDP to be 'RTP/AVP',
|
||||
'RTP/AVPF', 'RTP/SAVP', or 'RTP/SAVPF' even if a DTLS stream has been
|
||||
configured. This option can be set to improve interoperability with WebRTC
|
||||
clients that don't use the RFC defined transport for DTLS.
|
||||
|
||||
- The 'dtlsverify' option in chan_sip now has additional values besides
|
||||
'yes' and 'no'. If 'yes' is specified both the certificate and fingerprint
|
||||
will be verified. If 'no' is specified then neither the certificate or
|
||||
fingerprint is verified. If 'certificate' is specified then only the
|
||||
certificate is verified. If 'fingerprint' is specified then only the
|
||||
fingerprint is verified.
|
||||
|
||||
- A 'dtlsfingerprint' option has been added to chan_sip which allows the
|
||||
hash to be specified for the DTLS fingerprint placed in SDP. Supported
|
||||
values are 'sha-1' and 'sha-256' with 'sha-256' being the default.
|
||||
|
||||
- The 'progressinband=never' option is now more zealous in the persecution of
|
||||
progress messages coming from Asterisk. Channels bridged with a SIP channel
|
||||
that has 'progressinband=never' set will not be able to forward their
|
||||
progress indications through to the SIP device. chan_sip will now turn such
|
||||
progress indications into a 180 Ringing (if a 180 has not yet been
|
||||
transmitted) if 'progressinband=never'.
|
||||
|
||||
- The codec preference order in an SDP during an offer is slightly different
|
||||
than previous releases. Prior to Asterisk 13, the preference order of
|
||||
codecs used to be:
|
||||
(1) Our preferred codec
|
||||
(2) Our configured codecs
|
||||
(3) Any non-audio joint codecs
|
||||
|
||||
One of the ways the new media format architecture in Asterisk 13 improves
|
||||
performance is by reference counting formats, such that they can be reused
|
||||
in many places without additional allocation. To not require a large
|
||||
amount of locking, an instance of a format is immutable by convention.
|
||||
This works well except for formats with attributes. Since a media format
|
||||
with an attribute is a different object than the same format without an
|
||||
attribute, we have to carry over the formats with attributes from an
|
||||
inbound offer so that the correct attributes are offered in an outgoing
|
||||
INVITE request. This requires some subtle tweaks to the preference order
|
||||
to ensure that the media format with attributes is offered to a remote
|
||||
peer, as opposed to the same media format (but without attributes) that
|
||||
may be stored in the peer object.
|
||||
|
||||
All of this means that our offer offer list will now be:
|
||||
(1) Our preferred codec
|
||||
(2) Any joint codecs offered by the inbound offer
|
||||
(3) All other codecs that are not the preferred codec and not a joint
|
||||
codec offered by the inbound offer
|
||||
|
||||
chan_unistim:
|
||||
- The unistim.conf 'dateformat' has changed meaning of options values to conform
|
||||
values used inside Unistim protocol
|
||||
|
||||
- Added 'dtmf_duration' option with changing default operation to disable
|
||||
receivied dtmf playback on unistim phone
|
||||
|
||||
Core:
|
||||
|
||||
Account Codes:
|
||||
- accountcode behavior changed somewhat to add functional peeraccount
|
||||
support. The main change is that local channels now cross accountcode
|
||||
and peeraccount across the special bridge between the ;1 and ;2 channels
|
||||
just like channels between normal bridges. See the CHANGES file for
|
||||
more information.
|
||||
|
||||
ARI:
|
||||
- The ARI version has been changed to 1.5.0. This is to reflect backwards
|
||||
compatible changes made since 12.0.0 was released.
|
||||
|
||||
- Added a new ARI resource 'mailboxes' which allows the creation and
|
||||
modification of mailboxes managed by external MWI. Modules res_mwi_external
|
||||
and res_stasis_mailbox must be enabled to use this resource.
|
||||
|
||||
- Added new events for externally initiated transfers. The event
|
||||
BridgeBlindTransfer is now raised when a channel initiates a blind transfer
|
||||
of a bridge in the ARI controlled application to the dialplan; the
|
||||
BridgeAttendedTransfer event is raised when a channel initiates an
|
||||
attended transfer of a bridge in the ARI controlled application to the
|
||||
dialplan.
|
||||
|
||||
- Channel variables may now be specified as a body parameter to the
|
||||
POST /channels operation. The 'variables' key in the JSON is interpreted
|
||||
as a sequence of key/value pairs that will be added to the created channel
|
||||
as channel variables. Other parameters in the JSON body are treated as
|
||||
query parameters of the same name.
|
||||
|
||||
- A bug fix in bridge creation has caused a behavioural change in how
|
||||
subscriptions are created for bridges. A bridge created through ARI, does
|
||||
not, by itself, have a subscription created for any particular Stasis
|
||||
application. When a channel in a Stasis application joins a bridge, an
|
||||
implicit event subscription is created for that bridge as well. Previously,
|
||||
when a channel left such a bridge, the subscription was leaked; this allowed
|
||||
for later bridge events to continue to be pushed to the subscribed
|
||||
applications. That leak has been fixed; as a result, bridge events that were
|
||||
delivered after a channel left the bridge are no longer delivered. An
|
||||
application must subscribe to a bridge through the applications resource if
|
||||
it wishes to receive all events related to a bridge.
|
||||
|
||||
AMI:
|
||||
- The AMI version has been changed to 2.5.0. This is to reflect backwards
|
||||
compatible changes made since 12.0.0 was released.
|
||||
|
||||
- The DialStatus field in the DialEnd event can now have additional values.
|
||||
This includes ABORT, CONTINUE, and GOTO.
|
||||
|
||||
- The res_mwi_external_ami module can, if loaded, provide additional AMI
|
||||
actions and events that convey MWI state within Asterisk. This includes
|
||||
the MWIGet, MWIUpdate, and MWIDelete actions, as well as the MWIGet and
|
||||
MWIGetComplete events that occur in response to an MWIGet action.
|
||||
|
||||
- AMI now contains a new class authorization, 'security'. This is used with
|
||||
the following new events: FailedACL, InvalidAccountID, SessionLimit,
|
||||
MemoryLimit, LoadAverageLimit, RequestNotAllowed, AuthMethodNotAllowed,
|
||||
RequestBadFormat, SuccessfulAuth, UnexpectedAddress, ChallengeResponseFailed,
|
||||
InvalidPassword, ChallengeSent, and InvalidTransport.
|
||||
|
||||
- Bridge related events now have two additional fields: BridgeName and
|
||||
BridgeCreator. BridgeName is a descriptive name for the bridge;
|
||||
BridgeCreator is the name of the entity that created the bridge. This
|
||||
affects the following events: ConfbridgeStart, ConfbridgeEnd,
|
||||
ConfbridgeJoin, ConfbridgeLeave, ConfbridgeRecord, ConfbridgeStopRecord,
|
||||
ConfbridgeMute, ConfbridgeUnmute, ConfbridgeTalking, BlindTransfer,
|
||||
AttendedTransfer, BridgeCreate, BridgeDestroy, BridgeEnter, BridgeLeave
|
||||
|
||||
- MixMonitor AMI actions now require users to have authorization classes.
|
||||
* MixMonitor - system
|
||||
* MixMonitorMute - call or system
|
||||
* StopMixMonitor - call or system
|
||||
|
||||
- Removed the undocumented manager.conf block-sockets option. It interferes with
|
||||
TCP/TLS inactivity timeouts.
|
||||
|
||||
- The response to the PresenceState AMI action has historically contained two
|
||||
Message keys. The first of these is used as an informative message regarding
|
||||
the success/failure of the action; the second contains a Presence state
|
||||
specific message. Having two keys with the same unique name in an AMI
|
||||
message is cumbersome for some client; hence, the Presence specific Message
|
||||
has been deprecated. The message will now contain a PresenceMessage key
|
||||
for the presence specific information; the Message key containing presence
|
||||
information will be removed in the next major version of AMI.
|
||||
|
||||
- The manager.conf 'eventfilter' now takes an "extended" regular expression
|
||||
instead of a "basic" one.
|
||||
|
||||
CDRs:
|
||||
- The "endbeforehexten" setting now defaults to "yes", instead of "no".
|
||||
When set to "no", yhis setting will cause a new CDR to be generated when a
|
||||
channel enters into hangup logic (either the 'h' extension or a hangup
|
||||
handler subroutine). In general, this is not the preferred default: this
|
||||
causes extra CDRs to be generated for a channel in many common dialplans.
|
||||
|
||||
CLI commands:
|
||||
- "core show settings" now lists the current console verbosity in addition
|
||||
to the root console verbosity.
|
||||
|
||||
- "core set verbose" has not been able to support the by module verbose
|
||||
logging levels since verbose logging levels were made per console. That
|
||||
syntax is now removed and a silence option added in its place.
|
||||
|
||||
Logging:
|
||||
- The 'verbose' setting in logger.conf still takes an optional argument,
|
||||
specifying the verbosity level for each logging destination. However,
|
||||
the default is now to once again follow the current root console level.
|
||||
As a result, using the AMI Command action with "core set verbose" could
|
||||
again set the root console verbose level and affect the verbose level
|
||||
logged.
|
||||
|
||||
HTTP:
|
||||
- Added http.conf session_inactivity timer option to close HTTP connections
|
||||
that aren't doing anything.
|
||||
|
||||
- Added support for persistent HTTP connections. To enable persistent
|
||||
HTTP connections configure the keep alive time between HTTP requests. The
|
||||
keep alive time between HTTP requests is configured in http.conf with the
|
||||
session_keep_alive parameter.
|
||||
|
||||
Realtime Configuration:
|
||||
- WARNING: The database migration script that adds the 'extensions' table for
|
||||
realtime had to be modified due to an error when installing for MySQL. The
|
||||
'extensions' table's 'id' column was changed to be a primary key. This could
|
||||
potentially cause a migration problem. If so, it may be necessary to
|
||||
manually alter the affected table/column to bring it back in line with the
|
||||
migration scripts.
|
||||
|
||||
- New columns have been added to realtime tables for 'support_path' on
|
||||
ps_registrations and ps_aors and for 'path' on ps_contacts for the new
|
||||
SIP Path support in chan_pjsip.
|
||||
|
||||
- The following new tables have been added for pjsip realtime: 'ps_systems',
|
||||
'ps_globals', 'ps_tranports', 'ps_registrations'.
|
||||
|
||||
- The following columns were added to the 'ps_aors' realtime table:
|
||||
'maximum_expiration', 'outbound_proxy', and 'support_path'.
|
||||
|
||||
- The following columns were added to the 'ps_contacts' realtime table:
|
||||
'outbound_proxy', 'user_agent', and 'path'.
|
||||
|
||||
- New columns have been added to the ps_endpoints realtime table for the
|
||||
'media_address', 'redirect_method' and 'set_var' options. Also the
|
||||
'mwi_fromuser' column was renamed to 'mwi_from_user'. A new column
|
||||
'message_context' was added to let users configure how MESSAGE requests are
|
||||
routed to the dialplan.
|
||||
|
||||
- A new column was added to the 'ps_globals' realtime table for the 'debug'
|
||||
option.
|
||||
|
||||
- PJSIP endpoint columns 'tos_audio' and 'tos_video' have been changed from
|
||||
yes/no enumerators to string values. 'cos_audio' and 'cos_video' have been
|
||||
changed from yes/no enumerators to integer values. PJSIP transport column
|
||||
'tos' has been changed from a yes/no enumerator to a string value. 'cos' has
|
||||
been changed from a yes/no enumerator to an integer value.
|
||||
|
||||
- The 'queues' and 'queue_members' realtime tables have been added to the
|
||||
config Alembic scripts.
|
||||
|
||||
- A new set of Alembic scripts has been added for CDR tables. This will create
|
||||
a 'cdr' table with the default schema that Asterisk expects.
|
||||
|
||||
- A new upgrade script has been added that adds a 'queue_rules' table for
|
||||
app_queue. Users of app_queue can store queue rules in a database. It is
|
||||
important to note that app_queue only looks for this table on module load or
|
||||
module reload; for more information, see the CHANGES file.
|
||||
|
||||
Resources:
|
||||
|
||||
res_odbc:
|
||||
- The compatibility setting, allow_empty_string_in_nontext, has been removed.
|
||||
Empty column values will be stored as empty strings during realtime updates.
|
||||
|
||||
res_jabber:
|
||||
- This module was deprecated and has been removed. Users of this module should
|
||||
use res_xmpp instead.
|
||||
|
||||
res_http_websocket:
|
||||
- Added a compatibility option to ari.conf, sip.conf, and pjsip.conf
|
||||
'websocket_write_timeout'. When a websocket connection exists where Asterisk
|
||||
writes a substantial amount of data to the connected client, and the connected
|
||||
client is slow to process the received data, the socket may be disconnected.
|
||||
In such cases, it may be necessary to adjust this value.
|
||||
Default is 100 ms.
|
||||
Scripts:
|
||||
|
||||
safe_asterisk:
|
||||
- The safe_asterisk script was previously not installed on top of an existing
|
||||
version. This caused bug-fixes in that script not to be deployed. If your
|
||||
safe_asterisk script is customized, be sure to keep your changes. Custom
|
||||
values for variables should be created in *.sh file(s) inside
|
||||
ASTETCDIR/startup.d/. See ASTERISK-21965.
|
||||
|
||||
- Changed a log message in safe_asterisk and the $NOTIFY mail subject. If
|
||||
you use tools to parse either of them, update your parse functions
|
||||
accordingly. The changed strings are:
|
||||
- "Exited on signal $EXITSIGNAL" => "Asterisk exited on signal $EXITSIGNAL."
|
||||
- "Asterisk Died" => "Asterisk on $MACHINE died (sig $EXITSIGNAL)"
|
||||
|
||||
Utilities:
|
||||
- The refcounter program has been removed in favor of the refcounter.py script
|
||||
in contrib/scripts.
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
115
UPGRADE-14.txt
115
UPGRADE-14.txt
|
@ -1,115 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
|
||||
=== UPGRADE-11.txt -- Upgrade info for 10 to 11
|
||||
=== UPGRADE-12.txt -- Upgrade info for 11 to 12
|
||||
=== UPGRADE-13.txt -- Upgrade info for 12 to 13
|
||||
===========================================================
|
||||
|
||||
From 14.6.0 to 14.7.0:
|
||||
|
||||
Core:
|
||||
- ast_app_parse_timelen now returns an error if it encounters extra characters
|
||||
at the end of the string to be parsed.
|
||||
|
||||
From 14.4.0 to 14.5.0:
|
||||
|
||||
Core:
|
||||
- Support for embedded modules has been removed. This has not worked in
|
||||
many years. LOADABLE_MODULES menuselect option is also removed as
|
||||
loadable module support is now always enabled.
|
||||
|
||||
From 14.3.0 to 14.4.0:
|
||||
|
||||
res_rtp_asterisk:
|
||||
- The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP
|
||||
Data and Control Packets on a Single Port." For the PJSIP channel driver,
|
||||
chan_pjsip, you can set "rtcp_mux = yes" on a PJSIP endpoint in pjsip.conf
|
||||
to enable the feature. For chan_sip you can set "rtcp_mux = yes" either
|
||||
globally or on a per-peer basis in sip.conf.
|
||||
|
||||
New in 14.0.0
|
||||
|
||||
ARI:
|
||||
- The policy for when to send "Dial" events has changed. Previously, "Dial"
|
||||
events were sent on the calling channel's topic. However, starting in Asterisk
|
||||
14, if there is no calling channel on which to send the event, the event is
|
||||
instead sent on the called channel's topic. Note that for the ARI channels
|
||||
resource's dial operation, this means that the "Dial" events will always be
|
||||
sent on the called channel's topic.
|
||||
|
||||
Channel Drivers:
|
||||
|
||||
chan_dahdi:
|
||||
- For users using the FXO port (FXS signaling) distinctive ring detection
|
||||
feature, you will need to adjust the dringX count values. The count
|
||||
values now only record ring end events instead of any DAHDI event. A
|
||||
ring-ring-ring pattern would exceed the pattern limits and stop
|
||||
Caller-ID detection.
|
||||
|
||||
chan_sip:
|
||||
- The SIP dial string has been extended past the [!dnid] option by another
|
||||
exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI
|
||||
will now mean changes to the From-URI.
|
||||
|
||||
Core:
|
||||
- The REF_DEBUG compiler flag is now used to enable refdebug by default.
|
||||
The setting can be overridden in asterisk.conf by setting refdebug in
|
||||
the options category. No recompile is required to enable/disable it.
|
||||
|
||||
- Modified processing of command-line options to first parse only what
|
||||
is necessary to read asterisk.conf. Once asterisk.conf is fully loaded,
|
||||
the remaining options are processed. The -X option now applies to
|
||||
asterisk.conf only. To enable #exec for other config files you must
|
||||
set execincludes=yes in asterisk.conf. Any other option set on the
|
||||
command-line will now override the equivalent setting from asterisk.conf.
|
||||
|
||||
AMI:
|
||||
- The 'ModuleCheck' Action's Version key will no longer show the module
|
||||
version. The value will always be blank.
|
||||
|
||||
CLI:
|
||||
- The 'core show file version' command has been removed. When Asterisk
|
||||
moved to Git, the source control version support was removed. As a
|
||||
result, the CLi command was no longer useful and was removed as well.
|
||||
|
||||
Logging:
|
||||
- The first callid created is now 1 instead of 0. The value 0
|
||||
is now reserved to represent a lack of callid.
|
||||
|
||||
AMI:
|
||||
- The Command action now sends the output from the CLI command as a series
|
||||
of Output headers for each line instead of as a block of text with the
|
||||
--END COMMAND-- delimiter to match the output from other actions.
|
||||
|
||||
Commands that fail to execute (no such command, invalid syntax etc.) now
|
||||
return an Error response instead of Success.
|
||||
|
||||
app_amd:
|
||||
- The 'maximum_number_of_words' configuration option and parameter to the AMD
|
||||
application previously did not match the documented functionality + variable
|
||||
name. In Asterisk 13, a value of '3' would mean that if '3' words were detected,
|
||||
the result would be detection as a 'MACHINE'. As of this version, the value
|
||||
reflects the maximum words that if EXCEEDED (rather than reached), would
|
||||
result in detection as a machine. This means that you should update this
|
||||
value to be one higher than your previos value, if your previous value
|
||||
was working well for you.
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
|
@ -1,63 +0,0 @@
|
|||
===========================================================
|
||||
===
|
||||
=== Information for upgrading between Asterisk versions
|
||||
===
|
||||
=== These files document all the changes that MUST be taken
|
||||
=== into account when upgrading between the Asterisk
|
||||
=== versions listed below. These changes may require that
|
||||
=== you modify your configuration files, dialplan or (in
|
||||
=== some cases) source code if you have your own Asterisk
|
||||
=== modules or patches. These files also include advance
|
||||
=== notice of any functionality that has been marked as
|
||||
=== 'deprecated' and may be removed in a future release,
|
||||
=== along with the suggested replacement functionality.
|
||||
===
|
||||
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
|
||||
=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4
|
||||
=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6
|
||||
=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8
|
||||
=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10
|
||||
=== UPGRADE-11.txt -- Upgrade info for 10 to 11
|
||||
=== UPGRADE-12.txt -- Upgrade info for 11 to 12
|
||||
=== UPGRADE-13.txt -- Upgrade info for 12 to 13
|
||||
=== UPGRADE-14.txt -- Upgrade info for 13 to 14
|
||||
===========================================================
|
||||
|
||||
From 15.2.0 to 15.3.0:
|
||||
|
||||
res_pjsip
|
||||
------------------
|
||||
* Users who are matching endpoints by SIP header need to reevaluate their
|
||||
global "endpoint_identifier_order" option in light of the "ip" endpoint
|
||||
identifier method split into the "ip" and "header" endpoint identifier
|
||||
methods.
|
||||
|
||||
res_pjsip_endpoint_identifier_ip
|
||||
------------------
|
||||
* The endpoint identifier "ip" method previously recognized endpoints either
|
||||
by IP address or a matching SIP header. The "ip" endpoint identifier method
|
||||
is now split into the "ip" and "header" endpoint identifier methods. The
|
||||
"ip" endpoint identifier method only matches by IP address and the "header"
|
||||
endpoint identifier method only matches by SIP header. The split allows the
|
||||
user to control the relative priority of the IP address and the SIP header
|
||||
identification methods in the global "endpoint_identifier_order" option.
|
||||
e.g., If you have two type=identify sections where one matches by IP address
|
||||
for endpoint alice and the other matches by SIP header for endpoint bob then
|
||||
you can now predict which endpoint is matched when a request comes in that
|
||||
matches both.
|
||||
|
||||
New in 15.0.0:
|
||||
|
||||
Build System:
|
||||
- '--with-pjproject-bundled' is now the default when running ./configure
|
||||
It can be disabled with '--without-pjproject-bundled'.
|
||||
|
||||
Core:
|
||||
- Multi-stream support has been added so a channel can have multiple
|
||||
streams of the same type such as audio and video.
|
||||
|
||||
- The 'Data Retrieval API' has been removed. This API was not actively
|
||||
maintained, was not added to new modules (such as res_pjsip), and there
|
||||
exist better alternatives to acquire the same information, such as the
|
||||
ARI. As a result, the 'DataGet' AMI action as well as the 'data get'
|
||||
CLI command have been removed.
|
2632
UPGRADE.txt
2632
UPGRADE.txt
File diff suppressed because it is too large
Load Diff
|
@ -82,7 +82,7 @@
|
|||
/* Defaults */
|
||||
#define DEFAULT_CONTEXT "default"
|
||||
#define DEFAULT_H323ID "Asterisk PBX"
|
||||
#define DEFAULT_LOGFILE "/var/log/asterisk/h323_log"
|
||||
#define DEFAULT_LOGFILE "h323_log"
|
||||
#define DEFAULT_H323ACCNT "ast_h323"
|
||||
|
||||
/* Flags */
|
||||
|
@ -346,7 +346,8 @@ void onModeChanged(ooCallData *call, int t38mode);
|
|||
|
||||
extern OOH323EndPoint gH323ep;
|
||||
|
||||
static char gLogFile[256] = DEFAULT_LOGFILE;
|
||||
static char gLogFile[PATH_MAX] = DEFAULT_LOGFILE;
|
||||
static char gInitError[256] = "";
|
||||
static int gPort = 1720;
|
||||
static char gIP[2+8*4+7]; /* Max for IPv6 addr */
|
||||
struct ast_sockaddr bindaddr;
|
||||
|
@ -2856,7 +2857,7 @@ int reload_config(int reload)
|
|||
}
|
||||
|
||||
/* Inintialize everything to default */
|
||||
strcpy(gLogFile, DEFAULT_LOGFILE);
|
||||
snprintf(gLogFile, sizeof(gLogFile), "%s/%s", ast_config_AST_LOG_DIR, DEFAULT_LOGFILE);
|
||||
gPort = 1720;
|
||||
gIP[0] = '\0';
|
||||
strcpy(gCallerID, DEFAULT_H323ID);
|
||||
|
@ -3034,7 +3035,11 @@ int reload_config(int reload)
|
|||
ast_copy_string(gRASIP, v->value, sizeof(gRASIP));
|
||||
ast_verb(3, " == Setting RAS IP to %s\n", gRASIP);
|
||||
} else if (!strcasecmp(v->name, "logfile")) {
|
||||
ast_copy_string(gLogFile, v->value, sizeof(gLogFile));
|
||||
if (v->value[0] == '/') {
|
||||
ast_copy_string(gLogFile, v->value, sizeof(gLogFile));
|
||||
} else {
|
||||
snprintf(gLogFile, sizeof(gLogFile), "%s/%s", ast_config_AST_LOG_DIR, v->value);
|
||||
}
|
||||
} else if (!strcasecmp(v->name, "context")) {
|
||||
ast_copy_string(gContext, v->value, sizeof(gContext));
|
||||
ast_verb(3, " == Setting default context to %s\n", gContext);
|
||||
|
@ -3838,9 +3843,9 @@ static int load_module(void)
|
|||
if (!reload_config(0)) {
|
||||
|
||||
/* fire up the H.323 Endpoint */
|
||||
if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile)) {
|
||||
ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint-"
|
||||
"OOH323 Disabled\n");
|
||||
if (OO_OK != ooH323EpInitialize(OO_CALLMODE_AUDIOCALL, gLogFile, gInitError, sizeof(gInitError))) {
|
||||
ast_log(LOG_ERROR, "Failed to initialize OOH323 endpoint: %s"
|
||||
"OOH323 Disabled\n", gInitError);
|
||||
ao2_ref(gCap, -1);
|
||||
gCap = NULL;
|
||||
ao2_ref(ooh323_tech.capabilities, -1);
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "asterisk/udptl.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/format_cache.h"
|
||||
#include "asterisk/paths.h"
|
||||
|
||||
#include "ootypes.h"
|
||||
#include "ooUtils.h"
|
||||
|
|
|
@ -664,7 +664,7 @@ EXTERN int setPERBufferUsingCtxt (OOCTXT* pTarget, OOCTXT* pSource);
|
|||
/**
|
||||
* This function adds an integer parameter to an error information structure.
|
||||
* Parameter substitution is done in much the same way as it is done in C
|
||||
* printf statments. The base error message specification that goes along with
|
||||
* printf statements. The base error message specification that goes along with
|
||||
* a particular status code may have variable fields built in using '%'
|
||||
* modifiers. These would be replaced with actual parameter data.
|
||||
*
|
||||
|
@ -680,7 +680,7 @@ EXTERN int errAddIntParm (ASN1ErrInfo* pErrInfo, int errParm);
|
|||
/**
|
||||
* This function adds an string parameter to an error information structure.
|
||||
* Parameter substitution is done in much the same way as it is done in C
|
||||
* printf statments. The base error message specification that goes along with
|
||||
* printf statements. The base error message specification that goes along with
|
||||
* a particular status code may have variable fields built in using '%'
|
||||
* modifiers. These would be replaced with actual parameter data.
|
||||
*
|
||||
|
@ -697,7 +697,7 @@ EXTERN int errAddStrParm (ASN1ErrInfo* pErrInfo,
|
|||
/**
|
||||
* This function adds an unsigned integer parameter to an error information
|
||||
* structure. Parameter substitution is done in much the same way as it is done
|
||||
* in C printf statments. The base error message specification that goes along
|
||||
* in C printf statements. The base error message specification that goes along
|
||||
* with a particular status code may have variable fields built in using '%'
|
||||
* modifiers. These would be replaced with actual parameter data.
|
||||
*
|
||||
|
|
|
@ -34,7 +34,7 @@ ast_mutex_t bindPortLock;
|
|||
extern DList g_TimerList;
|
||||
|
||||
int ooH323EpInitialize
|
||||
(enum OOCallMode callMode, const char* tracefile)
|
||||
(enum OOCallMode callMode, const char* tracefile, char* errstr, int errstr_max)
|
||||
{
|
||||
|
||||
memset(&gH323ep, 0, sizeof(ooEndPoint));
|
||||
|
@ -46,7 +46,7 @@ int ooH323EpInitialize
|
|||
{
|
||||
if(strlen(tracefile)>= MAXFILENAME)
|
||||
{
|
||||
printf("Error:File name longer than allowed maximum %d\n",
|
||||
snprintf(errstr, errstr_max, "Error:File name longer than allowed maximum %d\n",
|
||||
MAXFILENAME-1);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ int ooH323EpInitialize
|
|||
gH323ep.fptraceFile = fopen(gH323ep.traceFile, "a");
|
||||
if(gH323ep.fptraceFile == NULL)
|
||||
{
|
||||
printf("Error:Failed to open trace file %s for write.\n",
|
||||
snprintf(errstr, errstr_max, "Error:Failed to open trace file %s for write.\n",
|
||||
gH323ep.traceFile);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ typedef struct OOH323EndPoint {
|
|||
* @return OO_OK, on success. OO_FAILED, on failure
|
||||
*/
|
||||
EXTERN int ooH323EpInitialize
|
||||
(enum OOCallMode callMode, const char* tracefile);
|
||||
(enum OOCallMode callMode, const char* tracefile, char* errstr, int errstr_max);
|
||||
|
||||
/**
|
||||
* This function is used to represent the H.323 application endpoint as
|
||||
|
|
|
@ -588,7 +588,7 @@ static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name
|
|||
}
|
||||
|
||||
if (state->numsubs > 127) {
|
||||
ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
|
||||
ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, S_OR(script, "unknown"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1457,9 +1457,9 @@ static void send_agent_logoff(struct ast_channel *chan, const char *agent, long
|
|||
|
||||
ast_assert(agent != NULL);
|
||||
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"agent", agent,
|
||||
"logintime", logintime);
|
||||
"logintime", (ast_json_int_t)logintime);
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
int ms = 0;
|
||||
|
||||
/* Figure out how long we waited */
|
||||
if (res > 0) {
|
||||
if (res >= 0) {
|
||||
ms = 2 * maxWaitTimeForFrame - res;
|
||||
}
|
||||
|
||||
|
@ -293,7 +293,7 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
break;
|
||||
}
|
||||
|
||||
if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_CNG) {
|
||||
if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) {
|
||||
/* Figure out how long the frame is in milliseconds */
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
framelength = (ast_codec_samples_count(f) / DEFAULT_SAMPLES_PER_MS);
|
||||
|
@ -410,6 +410,14 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
iTotalTime += ms;
|
||||
if (iTotalTime >= totalAnalysisTime) {
|
||||
ast_frfree(f);
|
||||
strcpy(amdStatus , "NOTSURE");
|
||||
sprintf(amdCause , "TOOLONG-%d", iTotalTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2019, Alexei Gradinari
|
||||
*
|
||||
* Alexei Gradinari <alex2grad@gmail.com>
|
||||
*
|
||||
* 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 Attended transfer by caller channel
|
||||
*
|
||||
* \author Alexei Gradinari <alex2grad@gmail.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>extended</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/features_config.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="AttendedTransfer" language="en_US">
|
||||
<synopsis>
|
||||
Attended transfer to the extension provided and TRANSFER_CONTEXT
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="exten" required="true">
|
||||
<para>Specify extension.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Queue up attended transfer to the specified extension in the <literal>TRANSFER_CONTEXT</literal>.</para>
|
||||
<para>Note that the attended transfer only work when two channels have answered and are bridged together.</para>
|
||||
<para>Make sure to set Attended Transfer DTMF feature <literal>atxfer</literal>
|
||||
and attended transfer is permitted.</para>
|
||||
<para>The result of the application will be reported in the <variable>ATTENDEDTRANSFERSTATUS</variable>
|
||||
channel variable:</para>
|
||||
<variablelist>
|
||||
<variable name="ATTENDEDTRANSFERSTATUS">
|
||||
<value name="SUCCESS">
|
||||
Transfer successfully queued.
|
||||
</value>
|
||||
<value name="FAILURE">
|
||||
Transfer failed.
|
||||
</value>
|
||||
<value name="NOTPERMITTED">
|
||||
Transfer not permitted.
|
||||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
</description>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static const char * const app = "AttendedTransfer";
|
||||
|
||||
static int attended_transfer_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *exten = NULL;
|
||||
const char *context = NULL;
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(exten);
|
||||
);
|
||||
char feature_code[AST_FEATURE_MAX_LEN];
|
||||
const char *digit;
|
||||
struct ast_frame f = { .frametype = AST_FRAME_DTMF };
|
||||
|
||||
if (ast_strlen_zero((char *)data)) {
|
||||
ast_log(LOG_WARNING, "%s requires an argument (exten)\n", app);
|
||||
pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "FAILURE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
context = pbx_builtin_getvar_helper(chan, "TRANSFER_CONTEXT");
|
||||
if (ast_strlen_zero(context)) {
|
||||
pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "NOTPERMITTED");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (ast_get_builtin_feature(chan, "atxfer", feature_code, sizeof(feature_code)) ||
|
||||
ast_strlen_zero(feature_code)) {
|
||||
pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "NOTPERMITTED");
|
||||
ast_channel_unlock(chan);
|
||||
return 0;
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
exten = args.exten;
|
||||
|
||||
for (digit = feature_code; *digit; ++digit) {
|
||||
f.subclass.integer = *digit;
|
||||
ast_queue_frame(chan, &f);
|
||||
}
|
||||
|
||||
for (digit = exten; *digit; ++digit) {
|
||||
f.subclass.integer = *digit;
|
||||
ast_queue_frame(chan, &f);
|
||||
}
|
||||
|
||||
f.subclass.integer = '#';
|
||||
ast_queue_frame(chan, &f);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFERSTATUS", "SUCCESS");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application_xml(app, attended_transfer_exec);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Attended transfer to the given extension");
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2019, Alexei Gradinari
|
||||
*
|
||||
* Alexei Gradinari <alex2grad@gmail.com>
|
||||
*
|
||||
* 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 Blind transfer by caller channel
|
||||
*
|
||||
* \author Alexei Gradinari <alex2grad@gmail.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>extended</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/bridge.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="BlindTransfer" language="en_US">
|
||||
<synopsis>
|
||||
Blind transfer channel(s) to the extension and context provided
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="exten" required="true">
|
||||
<para>Specify extension.</para>
|
||||
</parameter>
|
||||
<parameter name="context">
|
||||
<para>Optionally specify a context.
|
||||
By default, Asterisk will use the caller channel context.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Redirect all channels currently bridged to the caller channel to the
|
||||
specified destination.</para>
|
||||
<para>The result of the application will be reported in the <variable>BLINDTRANSFERSTATUS</variable>
|
||||
channel variable:</para>
|
||||
<variablelist>
|
||||
<variable name="BLINDTRANSFERSTATUS">
|
||||
<value name="SUCCESS">
|
||||
Transfer succeeded.
|
||||
</value>
|
||||
<value name="FAILURE">
|
||||
Transfer failed.
|
||||
</value>
|
||||
<value name="INVALID">
|
||||
Transfer invalid.
|
||||
</value>
|
||||
<value name="NOTPERMITTED">
|
||||
Transfer not permitted.
|
||||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
</description>
|
||||
</application>
|
||||
***/
|
||||
|
||||
static const char * const app = "BlindTransfer";
|
||||
|
||||
static int blind_transfer_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
char *exten = NULL;
|
||||
char *context = NULL;
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(exten);
|
||||
AST_APP_ARG(context);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero((char *)data)) {
|
||||
ast_log(LOG_WARNING, "%s requires an argument (exten)\n", app);
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "FAILURE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
exten = args.exten;
|
||||
if (ast_strlen_zero(args.context)) {
|
||||
context = (char *)ast_channel_context(chan);
|
||||
} else {
|
||||
context = args.context;
|
||||
}
|
||||
|
||||
switch (ast_bridge_transfer_blind(1, chan, exten, context, NULL, NULL)) {
|
||||
case AST_BRIDGE_TRANSFER_NOT_PERMITTED:
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "NOTPERMITTED");
|
||||
break;
|
||||
case AST_BRIDGE_TRANSFER_INVALID:
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "INVALID");
|
||||
break;
|
||||
case AST_BRIDGE_TRANSFER_FAIL:
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "FAILURE");
|
||||
break;
|
||||
case AST_BRIDGE_TRANSFER_SUCCESS:
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "SUCCESS");
|
||||
break;
|
||||
default:
|
||||
pbx_builtin_setvar_helper(chan, "BLINDTRANSFERSTATUS", "FAILURE");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application_xml(app, blind_transfer_exec);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Blind transfer channel to the given destination");
|
|
@ -178,6 +178,9 @@ static int chanavail_exec(struct ast_channel *chan, const char *data)
|
|||
snprintf(tmp, sizeof(tmp), "%d", status);
|
||||
ast_str_append(&tmp_availcause, 0, "%s%s", ast_str_strlen(tmp_availcause) ? "&" : "", tmp);
|
||||
|
||||
/* Disable CDR for this temporary channel. */
|
||||
ast_cdr_set_property(ast_channel_name(tempchan), AST_CDR_FLAG_DISABLE_ALL);
|
||||
|
||||
ast_hangup(tempchan);
|
||||
tempchan = NULL;
|
||||
|
||||
|
|
|
@ -576,6 +576,10 @@ static void send_conf_stasis(struct confbridge_conference *conference, struct as
|
|||
return;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
|
||||
conf_send_event_to_participants(conference, chan, msg);
|
||||
}
|
||||
|
||||
if (channel_topic) {
|
||||
stasis_publish(ast_channel_topic(chan), msg);
|
||||
} else {
|
||||
|
@ -583,6 +587,43 @@ static void send_conf_stasis(struct confbridge_conference *conference, struct as
|
|||
}
|
||||
}
|
||||
|
||||
static void send_conf_stasis_snapshots(struct confbridge_conference *conference,
|
||||
struct ast_channel_snapshot *chan_snapshot, struct stasis_message_type *type,
|
||||
struct ast_json *extras)
|
||||
{
|
||||
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
|
||||
RAII_VAR(struct ast_bridge_snapshot *, bridge_snapshot, NULL, ao2_cleanup);
|
||||
|
||||
json_object = ast_json_pack("{s: s}",
|
||||
"conference", conference->name);
|
||||
if (!json_object) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (extras) {
|
||||
ast_json_object_update(json_object, extras);
|
||||
}
|
||||
|
||||
ast_bridge_lock(conference->bridge);
|
||||
bridge_snapshot = ast_bridge_snapshot_create(conference->bridge);
|
||||
ast_bridge_unlock(conference->bridge);
|
||||
if (!bridge_snapshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg = ast_bridge_blob_create_from_snapshots(type,
|
||||
bridge_snapshot,
|
||||
chan_snapshot,
|
||||
json_object);
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_publish(ast_bridge_topic(conference->bridge), msg);
|
||||
}
|
||||
|
||||
|
||||
static void send_conf_start_event(struct confbridge_conference *conference)
|
||||
{
|
||||
send_conf_stasis(conference, NULL, confbridge_start_type(), NULL, 0);
|
||||
|
@ -1107,13 +1148,15 @@ static void destroy_conference_bridge(void *obj)
|
|||
if (conference->playback_queue) {
|
||||
struct hangup_data hangup;
|
||||
hangup_data_init(&hangup, conference);
|
||||
ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup);
|
||||
|
||||
ast_mutex_lock(&hangup.lock);
|
||||
while (!hangup.hungup) {
|
||||
ast_cond_wait(&hangup.cond, &hangup.lock);
|
||||
if (!ast_taskprocessor_push(conference->playback_queue, hangup_playback, &hangup)) {
|
||||
ast_mutex_lock(&hangup.lock);
|
||||
while (!hangup.hungup) {
|
||||
ast_cond_wait(&hangup.cond, &hangup.lock);
|
||||
}
|
||||
ast_mutex_unlock(&hangup.lock);
|
||||
}
|
||||
ast_mutex_unlock(&hangup.lock);
|
||||
|
||||
hangup_data_destroy(&hangup);
|
||||
} else {
|
||||
/* Playback queue is not yet allocated. Just hang up the channel straight */
|
||||
|
@ -1354,7 +1397,7 @@ int conf_handle_inactive_waitmarked(struct confbridge_user *user)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int conf_handle_only_unmarked(struct confbridge_user *user)
|
||||
int conf_handle_only_person(struct confbridge_user *user)
|
||||
{
|
||||
/* If audio prompts have not been quieted or this prompt quieted play it on out */
|
||||
if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET | USER_OPT_NOONLYPERSON)) {
|
||||
|
@ -1473,6 +1516,126 @@ static int push_announcer(struct confbridge_conference *conference)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void confbridge_unlock_and_unref(void *obj)
|
||||
{
|
||||
struct confbridge_conference *conference = obj;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
ao2_unlock(conference);
|
||||
ao2_ref(conference, -1);
|
||||
}
|
||||
|
||||
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg)
|
||||
{
|
||||
struct ast_channel_snapshot *old_snapshot;
|
||||
struct ast_channel_snapshot *new_snapshot;
|
||||
char *confbr_name = NULL;
|
||||
char *comma;
|
||||
RAII_VAR(struct confbridge_conference *, conference, NULL, confbridge_unlock_and_unref);
|
||||
struct confbridge_user *user = NULL;
|
||||
int found_user = 0;
|
||||
struct ast_json *json_object;
|
||||
|
||||
if (msg->to_transferee.channel_snapshot
|
||||
&& strcmp(msg->to_transferee.channel_snapshot->appl, "ConfBridge") == 0
|
||||
&& msg->target) {
|
||||
/* We're transferring a bridge to an extension */
|
||||
old_snapshot = msg->to_transferee.channel_snapshot;
|
||||
new_snapshot = msg->target;
|
||||
} else if (msg->to_transfer_target.channel_snapshot
|
||||
&& strcmp(msg->to_transfer_target.channel_snapshot->appl, "ConfBridge") == 0
|
||||
&& msg->transferee) {
|
||||
/* We're transferring a call to a bridge */
|
||||
old_snapshot = msg->to_transfer_target.channel_snapshot;
|
||||
new_snapshot = msg->transferee;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Could not determine proper channels\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* old_snapshot->data should have the original parameters passed to
|
||||
* the ConfBridge app:
|
||||
* conference[,bridge_profile[,user_profile[,menu]]]
|
||||
* We'll use "conference" to look up the bridge.
|
||||
*
|
||||
* We _could_ use old_snapshot->bridgeid to get the bridge but
|
||||
* that would involve locking the conference_bridges container
|
||||
* and iterating over it looking for a matching bridge.
|
||||
*/
|
||||
if (ast_strlen_zero(old_snapshot->data)) {
|
||||
ast_log(LOG_ERROR, "Channel '%s' didn't have app data set\n", old_snapshot->name);
|
||||
return;
|
||||
}
|
||||
confbr_name = ast_strdupa(old_snapshot->data);
|
||||
comma = strchr(confbr_name, ',');
|
||||
if (comma) {
|
||||
*comma = '\0';
|
||||
}
|
||||
|
||||
ast_debug(1, "Confbr: %s Leaving: %s Joining: %s\n", confbr_name, old_snapshot->name, new_snapshot->name);
|
||||
|
||||
conference = ao2_find(conference_bridges, confbr_name, OBJ_SEARCH_KEY);
|
||||
if (!conference) {
|
||||
ast_log(LOG_ERROR, "Conference bridge '%s' not found\n", confbr_name);
|
||||
return;
|
||||
}
|
||||
ao2_lock(conference);
|
||||
|
||||
/*
|
||||
* We need to grab the user profile for the departing user in order to
|
||||
* properly format the join/leave messages.
|
||||
*/
|
||||
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
|
||||
if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
|
||||
found_user = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't find the user in the active list, try the waiting list.
|
||||
*/
|
||||
if (!found_user && conference->waitingusers) {
|
||||
AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
|
||||
if (strcasecmp(ast_channel_name(user->chan), old_snapshot->name) == 0) {
|
||||
found_user = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_user) {
|
||||
ast_log(LOG_ERROR, "Unable to find user profile for channel '%s' in bridge '%s'\n",
|
||||
old_snapshot->name, confbr_name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're going to use the existing user profile to create the messages.
|
||||
*/
|
||||
json_object = ast_json_pack("{s: b}",
|
||||
"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN)
|
||||
);
|
||||
if (!json_object) {
|
||||
return;
|
||||
}
|
||||
|
||||
send_conf_stasis_snapshots(conference, old_snapshot, confbridge_leave_type(), json_object);
|
||||
ast_json_unref(json_object);
|
||||
|
||||
json_object = ast_json_pack("{s: b, s: b}",
|
||||
"admin", ast_test_flag(&user->u_profile, USER_OPT_ADMIN),
|
||||
"muted", user->muted);
|
||||
if (!json_object) {
|
||||
return;
|
||||
}
|
||||
send_conf_stasis_snapshots(conference, new_snapshot, confbridge_join_type(), json_object);
|
||||
ast_json_unref(json_object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Join a conference bridge
|
||||
*
|
||||
|
@ -1559,9 +1722,19 @@ static struct confbridge_conference *join_conference_bridge(const char *conferen
|
|||
ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST);
|
||||
} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST)) {
|
||||
ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST);
|
||||
} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL)) {
|
||||
ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL);
|
||||
} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL)) {
|
||||
ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL);
|
||||
} else if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL)) {
|
||||
ast_brige_set_remb_behavior(conference->bridge, AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
|
||||
ast_bridge_set_send_sdp_label(conference->bridge, 1);
|
||||
}
|
||||
|
||||
/* Link it into the conference bridges container */
|
||||
if (!ao2_link(conference_bridges, conference)) {
|
||||
ao2_ref(conference, -1);
|
||||
|
@ -2311,6 +2484,25 @@ static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct confbridge_hook_data {
|
||||
struct confbridge_conference *conference;
|
||||
struct confbridge_user *user;
|
||||
enum ast_bridge_hook_type hook_type;
|
||||
};
|
||||
|
||||
static int send_event_hook_callback(struct ast_bridge_channel *bridge_channel, void *data)
|
||||
{
|
||||
struct confbridge_hook_data *hook_data = data;
|
||||
|
||||
if (hook_data->hook_type == AST_BRIDGE_HOOK_TYPE_JOIN) {
|
||||
send_join_event(hook_data->user, hook_data->conference);
|
||||
} else {
|
||||
send_leave_event(hook_data->user, hook_data->conference);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief The ConfBridge application */
|
||||
static int confbridge_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
|
@ -2328,6 +2520,9 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
|
|||
.tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
|
||||
.tech_args.drop_silence = 0,
|
||||
};
|
||||
struct confbridge_hook_data *join_hook_data;
|
||||
struct confbridge_hook_data *leave_hook_data;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(conf_name);
|
||||
AST_APP_ARG(b_profile_name);
|
||||
|
@ -2510,8 +2705,39 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
|
|||
|
||||
conf_moh_unsuspend(&user);
|
||||
|
||||
/* Join our conference bridge for real */
|
||||
send_join_event(&user, conference);
|
||||
join_hook_data = ast_malloc(sizeof(*join_hook_data));
|
||||
if (!join_hook_data) {
|
||||
res = -1;
|
||||
goto confbridge_cleanup;
|
||||
}
|
||||
join_hook_data->user = &user;
|
||||
join_hook_data->conference = conference;
|
||||
join_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_JOIN;
|
||||
res = ast_bridge_join_hook(&user.features, send_event_hook_callback,
|
||||
join_hook_data, ast_free_ptr, 0);
|
||||
if (res) {
|
||||
ast_free(join_hook_data);
|
||||
ast_log(LOG_ERROR, "Couldn't add bridge join hook for channel '%s'\n", ast_channel_name(chan));
|
||||
goto confbridge_cleanup;
|
||||
}
|
||||
|
||||
leave_hook_data = ast_malloc(sizeof(*leave_hook_data));
|
||||
if (!leave_hook_data) {
|
||||
/* join_hook_data is cleaned up by ast_bridge_features_cleanup via the goto */
|
||||
res = -1;
|
||||
goto confbridge_cleanup;
|
||||
}
|
||||
leave_hook_data->user = &user;
|
||||
leave_hook_data->conference = conference;
|
||||
leave_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_LEAVE;
|
||||
res = ast_bridge_leave_hook(&user.features, send_event_hook_callback,
|
||||
leave_hook_data, ast_free_ptr, 0);
|
||||
if (res) {
|
||||
/* join_hook_data is cleaned up by ast_bridge_features_cleanup via the goto */
|
||||
ast_free(leave_hook_data);
|
||||
ast_log(LOG_ERROR, "Couldn't add bridge leave hook for channel '%s'\n", ast_channel_name(chan));
|
||||
goto confbridge_cleanup;
|
||||
}
|
||||
|
||||
if (ast_bridge_join_hook(&user.features, join_callback, NULL, NULL, 0)) {
|
||||
async_play_sound_ready(user.chan);
|
||||
|
@ -2533,8 +2759,6 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
|
|||
pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP");
|
||||
}
|
||||
|
||||
send_leave_event(&user, conference);
|
||||
|
||||
/* if we're shutting down, don't attempt to do further processing */
|
||||
if (ast_shutting_down()) {
|
||||
/*
|
||||
|
@ -4135,8 +4359,9 @@ static int load_module(void)
|
|||
}
|
||||
|
||||
/* Create a container to hold the conference bridges */
|
||||
conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS,
|
||||
conference_bridge_hash_cb, conference_bridge_cmp_cb);
|
||||
conference_bridges = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
CONFERENCE_BRIDGE_BUCKETS,
|
||||
conference_bridge_hash_cb, NULL, conference_bridge_cmp_cb);
|
||||
if (!conference_bridges) {
|
||||
unload_module();
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
|
|
184
apps/app_dial.c
184
apps/app_dial.c
|
@ -142,11 +142,9 @@
|
|||
a call to be answered. Exit to that extension if it exists in the
|
||||
current context, or the context defined in the <variable>EXITCONTEXT</variable> variable,
|
||||
if it exists.</para>
|
||||
<note>
|
||||
<para>Many SIP and ISDN phones cannot send DTMF digits until the call is
|
||||
connected. If you wish to use this option with these phones, you
|
||||
can use the <literal>Answer</literal> application before dialing.</para>
|
||||
</note>
|
||||
<para>NOTE: Many SIP and ISDN phones cannot send DTMF digits until the call is
|
||||
connected. If you wish to use this option with these phones, you
|
||||
can use the <literal>Answer</literal> application before dialing.</para>
|
||||
</option>
|
||||
<option name="D" argsep=":">
|
||||
<argument name="called" />
|
||||
|
@ -177,21 +175,15 @@
|
|||
<argument name="priority" required="true" />
|
||||
<para>When the caller hangs up, transfer the <emphasis>called</emphasis> party
|
||||
to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<note>
|
||||
<para>Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
</note>
|
||||
<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</emphasis> party to the next priority of the current extension
|
||||
and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<note>
|
||||
<para>Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
</note>
|
||||
<note>
|
||||
<para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
|
||||
</note>
|
||||
<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="g">
|
||||
<para>Proceed with dialplan execution at the next priority in the current extension if the
|
||||
|
@ -204,9 +196,7 @@
|
|||
<para>If the call is answered, transfer the calling party to
|
||||
the specified <replaceable>priority</replaceable> and the called party to the specified
|
||||
<replaceable>priority</replaceable> plus one.</para>
|
||||
<note>
|
||||
<para>You cannot use any additional action post answer options in conjunction with this option.</para>
|
||||
</note>
|
||||
<para>NOTE: You cannot use any additional action post answer options in conjunction with this option.</para>
|
||||
</option>
|
||||
<option name="h">
|
||||
<para>Allow the called party to hang up by sending the DTMF sequence
|
||||
|
@ -215,12 +205,10 @@
|
|||
<option name="H">
|
||||
<para>Allow the calling party to hang up by sending the DTMF sequence
|
||||
defined for disconnect in <filename>features.conf</filename>.</para>
|
||||
<note>
|
||||
<para>Many SIP and ISDN phones cannot send DTMF digits until the call is
|
||||
connected. If you wish to allow DTMF disconnect before the dialed
|
||||
party answers with these phones, you can use the <literal>Answer</literal>
|
||||
application before dialing.</para>
|
||||
</note>
|
||||
<para>NOTE: Many SIP and ISDN phones cannot send DTMF digits until the call is
|
||||
connected. If you wish to allow DTMF disconnect before the dialed
|
||||
party answers with these phones, you can use the <literal>Answer</literal>
|
||||
application before dialing.</para>
|
||||
</option>
|
||||
<option name="i">
|
||||
<para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
|
||||
|
@ -316,18 +304,14 @@
|
|||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
<note>
|
||||
<para>You cannot use any additional action post answer options in conjunction
|
||||
with this option. Also, pbx services are run on the peer (called) channel,
|
||||
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this macro.</para>
|
||||
</note>
|
||||
<warning><para>Be aware of the limitations that macros have, specifically with regards to use of
|
||||
<para>NOTE: You cannot use any additional action post answer options in conjunction
|
||||
with this option. Also, pbx services are run on the peer (called) channel,
|
||||
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this macro.</para>
|
||||
<para>WARNING: Be aware of the limitations that macros have, specifically with regards to use of
|
||||
the <literal>WaitExten</literal> application. For more information, see the documentation for
|
||||
<literal>Macro()</literal>.</para></warning>
|
||||
<note>
|
||||
<para>Macros are deprecated, GoSub should be used instead,
|
||||
see the <literal>U</literal> option.</para>
|
||||
</note>
|
||||
<literal>Macro()</literal>.</para>
|
||||
<para>NOTE: Macros are deprecated, GoSub should be used instead,
|
||||
see the <literal>U</literal> option.</para>
|
||||
</option>
|
||||
<option name="n">
|
||||
<argument name="delete">
|
||||
|
@ -392,10 +376,8 @@
|
|||
to send no cause. See the <filename>causes.h</filename> file for the
|
||||
full list of valid causes and names.
|
||||
</para>
|
||||
<note>
|
||||
<para>chan_sip does not support setting the cause on a CANCEL to anything
|
||||
other than ANSWERED_ELSEWHERE.</para>
|
||||
</note>
|
||||
<para>NOTE: chan_sip does not support setting the cause on a CANCEL to anything
|
||||
other than ANSWERED_ELSEWHERE.</para>
|
||||
</option>
|
||||
<option name="r">
|
||||
<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
|
||||
|
@ -430,7 +412,8 @@
|
|||
</option>
|
||||
<option name="U" argsep="^">
|
||||
<argument name="x" required="true">
|
||||
<para>Name of the subroutine to execute via <literal>Gosub</literal></para>
|
||||
<para>Name of the subroutine context to execute via <literal>Gosub</literal>.
|
||||
The subroutine execution starts in the named context at the s exten and priority 1.</para>
|
||||
</argument>
|
||||
<argument name="arg" multiple="true" required="false">
|
||||
<para>Arguments for the <literal>Gosub</literal> routine</para>
|
||||
|
@ -459,11 +442,9 @@
|
|||
</value>
|
||||
</variable>
|
||||
</variablelist>
|
||||
<note>
|
||||
<para>You cannot use any additional action post answer options in conjunction
|
||||
with this option. Also, pbx services are run on the peer (called) channel,
|
||||
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this routine.</para>
|
||||
</note>
|
||||
<para>NOTE: You cannot use any additional action post answer options in conjunction
|
||||
with this option. Also, pbx services are run on the <emphasis>called</emphasis> channel,
|
||||
so you will not be able to set timeouts via the <literal>TIMEOUT()</literal> function in this routine.</para>
|
||||
</option>
|
||||
<option name="u">
|
||||
<argument name = "x" required="true">
|
||||
|
@ -548,27 +529,29 @@
|
|||
<example title="Dial with pre-dial subroutines">
|
||||
[default]
|
||||
|
||||
exten => callee_channel,1,NoOp()
|
||||
exten => callee_channel,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
|
||||
same => n,Log(NOTICE, I'm called on channel ${CHANNEL} prior to it starting the dial attempt)
|
||||
same => n,Return()
|
||||
|
||||
exten => called_channel,1,NoOp()
|
||||
exten => called_channel,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
|
||||
same => n,Log(NOTICE, I'm called on outbound channel ${CHANNEL} prior to it being used to dial someone)
|
||||
same => n,Return()
|
||||
|
||||
exten => _X.,1,NoOp()
|
||||
same => n,Dial(PJSIP/alice,,b(default^called_channel^1)B(default^callee_channel^1))
|
||||
same => n,Dial(PJSIP/alice,,b(default^called_channel^1(my_gosub_arg1^my_gosub_arg2))B(default^callee_channel^1(my_gosub_arg1^my_gosub_arg2)))
|
||||
same => n,Hangup()
|
||||
</example>
|
||||
<example title="Dial with post-answer subroutine executed on outbound channel">
|
||||
[default]
|
||||
[my_gosub_routine]
|
||||
|
||||
exten => called_channel,1,NoOp()
|
||||
exten => s,1,NoOp(ARG1=${ARG1} ARG2=${ARG2})
|
||||
same => n,Playback(hello)
|
||||
same => n,Return()
|
||||
|
||||
[default]
|
||||
|
||||
exten => _X.,1,NoOp()
|
||||
same => n,Dial(PJSIP/alice,,U(default^called_channel^1))
|
||||
same => n,Dial(PJSIP/alice,,U(my_gosub_routine^my_gosub_arg1^my_gosub_arg2))
|
||||
same => n,Hangup()
|
||||
</example>
|
||||
<example title="Dial into ConfBridge using 'G' option">
|
||||
|
@ -582,9 +565,27 @@
|
|||
<variable name="DIALEDTIME">
|
||||
<para>This is the time from dialing a channel until when it is disconnected.</para>
|
||||
</variable>
|
||||
<variable name="DIALEDTIME_MS">
|
||||
<para>This is the milliseconds version of the DIALEDTIME variable.</para>
|
||||
</variable>
|
||||
<variable name="ANSWEREDTIME">
|
||||
<para>This is the amount of time for actual call.</para>
|
||||
</variable>
|
||||
<variable name="ANSWEREDTIME_MS">
|
||||
<para>This is the milliseconds version of the ANSWEREDTIME variable.</para>
|
||||
</variable>
|
||||
<variable name="RINGTIME">
|
||||
<para>This is the time from creating the channel to the first RINGING event received. Empty if there was no ring.</para>
|
||||
</variable>
|
||||
<variable name="RINGTIME_MS">
|
||||
<para>This is the milliseconds version of the RINGTIME variable.</para>
|
||||
</variable>
|
||||
<variable name="PROGRESSTIME">
|
||||
<para>This is the time from creating the channel to the first PROGRESS event received. Empty if there was no such event.</para>
|
||||
</variable>
|
||||
<variable name="PROGRESSTIME_MS">
|
||||
<para>This is the milliseconds version of the PROGRESSTIME variable.</para>
|
||||
</variable>
|
||||
<variable name="DIALEDPEERNAME">
|
||||
<para>The name of the outbound channel that answered the call.</para>
|
||||
</variable>
|
||||
|
@ -1179,6 +1180,23 @@ static void update_connected_line_from_peer(struct ast_channel *chan, struct ast
|
|||
ast_party_connected_line_free(&connected_caller);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \pre chan is locked
|
||||
*/
|
||||
static void set_duration_var(struct ast_channel *chan, const char *var_base, int64_t duration)
|
||||
{
|
||||
char buf[32];
|
||||
char full_var_name[128];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%" PRId64, duration / 1000);
|
||||
pbx_builtin_setvar_helper(chan, var_base, buf);
|
||||
|
||||
snprintf(full_var_name, sizeof(full_var_name), "%s_MS", var_base);
|
||||
snprintf(buf, sizeof(buf), "%" PRId64, duration);
|
||||
pbx_builtin_setvar_helper(chan, full_var_name, buf);
|
||||
}
|
||||
|
||||
static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
||||
struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
|
||||
char *opt_args[],
|
||||
|
@ -1201,6 +1219,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
int is_cc_recall;
|
||||
int cc_frame_received = 0;
|
||||
int num_ringing = 0;
|
||||
int sent_ring = 0;
|
||||
int sent_progress = 0;
|
||||
struct timeval start = ast_tvnow();
|
||||
|
||||
if (single) {
|
||||
|
@ -1474,6 +1494,23 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_indicate(in, AST_CONTROL_RINGING);
|
||||
pa->sentringing++;
|
||||
}
|
||||
if (!sent_ring) {
|
||||
struct timeval now, then;
|
||||
int64_t diff;
|
||||
|
||||
now = ast_tvnow();
|
||||
|
||||
ast_channel_lock(in);
|
||||
ast_channel_stage_snapshot(in);
|
||||
|
||||
then = ast_channel_creationtime(c);
|
||||
diff = ast_tvzero(then) ? 0 : ast_tvdiff_ms(now, then);
|
||||
set_duration_var(in, "RINGTIME", diff);
|
||||
|
||||
ast_channel_stage_snapshot_done(in);
|
||||
ast_channel_unlock(in);
|
||||
sent_ring = 1;
|
||||
}
|
||||
}
|
||||
ast_channel_publish_dial(in, c, NULL, "RINGING");
|
||||
break;
|
||||
|
@ -1489,6 +1526,23 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_indicate(in, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
}
|
||||
if (!sent_progress) {
|
||||
struct timeval now, then;
|
||||
int64_t diff;
|
||||
|
||||
now = ast_tvnow();
|
||||
|
||||
ast_channel_lock(in);
|
||||
ast_channel_stage_snapshot(in);
|
||||
|
||||
then = ast_channel_creationtime(c);
|
||||
diff = ast_tvzero(then) ? 0 : ast_tvdiff_ms(now, then);
|
||||
set_duration_var(in, "PROGRESSTIME", diff);
|
||||
|
||||
ast_channel_stage_snapshot_done(in);
|
||||
ast_channel_unlock(in);
|
||||
sent_progress = 1;
|
||||
}
|
||||
if (!ast_strlen_zero(dtmf_progress)) {
|
||||
ast_verb(3,
|
||||
"Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n",
|
||||
|
@ -1750,12 +1804,20 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
ast_indicate(o->chan, f->subclass.integer);
|
||||
break;
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
|
||||
ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_REDIRECTING:
|
||||
if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
|
||||
ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
|
@ -2067,18 +2129,12 @@ static int setup_privacy_args(struct privacy_args *pa,
|
|||
|
||||
static void end_bridge_callback(void *data)
|
||||
{
|
||||
char buf[80];
|
||||
time_t end;
|
||||
struct ast_channel *chan = data;
|
||||
|
||||
time(&end);
|
||||
|
||||
ast_channel_lock(chan);
|
||||
ast_channel_stage_snapshot(chan);
|
||||
snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
|
||||
pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
|
||||
snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
|
||||
pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
|
||||
set_duration_var(chan, "ANSWEREDTIME", ast_channel_get_up_time_ms(chan));
|
||||
set_duration_var(chan, "DIALEDTIME", ast_channel_get_duration_ms(chan));
|
||||
ast_channel_stage_snapshot_done(chan);
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
|
@ -2220,7 +2276,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
|
||||
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
|
||||
pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
|
||||
pbx_builtin_setvar_helper(chan, "ANSWEREDTIME_MS", "");
|
||||
pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
|
||||
pbx_builtin_setvar_helper(chan, "DIALEDTIME_MS", "");
|
||||
pbx_builtin_setvar_helper(chan, "RINGTIME", "");
|
||||
pbx_builtin_setvar_helper(chan, "RINGTIME_MS", "");
|
||||
pbx_builtin_setvar_helper(chan, "PROGRESSTIME", "");
|
||||
pbx_builtin_setvar_helper(chan, "PROGRESSTIME_MS", "");
|
||||
ast_channel_stage_snapshot_done(chan);
|
||||
max_forwards = ast_max_forwards_get(chan);
|
||||
ast_channel_unlock(chan);
|
||||
|
@ -2852,7 +2914,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
chans[0] = chan;
|
||||
chans[1] = peer;
|
||||
|
||||
/* we need to stream the announcement while monitoring the caller for a hangup */
|
||||
/* we need to stream the announcement to the called party when the OPT_ARG_ANNOUNCE (-A) is setted */
|
||||
|
||||
/* stream the file */
|
||||
res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], ast_channel_language(peer));
|
||||
|
|
|
@ -224,7 +224,7 @@ struct findme_user {
|
|||
long digts;
|
||||
int ynidx;
|
||||
int state;
|
||||
char dialarg[256];
|
||||
char dialarg[768];
|
||||
/*! Collected digits to accept/decline the call. */
|
||||
char yn[MAX_YN_STRING];
|
||||
/*! TRUE if the outgoing call is answered. */
|
||||
|
@ -915,6 +915,11 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|||
/* Ignore going off hook and flash */
|
||||
break;
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
|
||||
ast_verb(3, "Connected line update from %s prevented.\n",
|
||||
ast_channel_name(winner));
|
||||
break;
|
||||
}
|
||||
if (!tmpuser) {
|
||||
/*
|
||||
* Hold connected line update from caller until we have a
|
||||
|
@ -930,11 +935,6 @@ static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_us
|
|||
tpargs->pending_in_connected_update = 1;
|
||||
}
|
||||
ast_party_connected_line_free(&connected);
|
||||
break;
|
||||
}
|
||||
if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
|
||||
ast_verb(3, "Connected line update from %s prevented.\n",
|
||||
ast_channel_name(winner));
|
||||
} else {
|
||||
ast_verb(3,
|
||||
"%s connected line has changed. Saving it until answer.\n",
|
||||
|
|
|
@ -1624,8 +1624,14 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
|
|||
|
||||
ast_format_cap_append(cap_slin, ast_format_slin, 0);
|
||||
/* Make a new one */
|
||||
if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
|
||||
!(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
|
||||
cnf = ast_calloc(1, sizeof(*cnf));
|
||||
if (!cnf) {
|
||||
goto cnfout;
|
||||
}
|
||||
|
||||
cnf->usercontainer = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
NULL, user_no_cmp);
|
||||
if (!cnf->usercontainer) {
|
||||
goto cnfout;
|
||||
}
|
||||
|
||||
|
@ -3424,7 +3430,9 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
|
|||
user->chan = chan;
|
||||
user->userflags = *confflags;
|
||||
user->adminflags = ast_test_flag64(confflags, CONFFLAG_STARTMUTED) ? ADMINFLAG_SELFMUTED : 0;
|
||||
user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
|
||||
if (!ast_test_flag64(confflags, CONFFLAG_ADMIN)) {
|
||||
user->adminflags |= (conf->gmuted) ? ADMINFLAG_MUTED : 0;
|
||||
}
|
||||
user->talking = -1;
|
||||
|
||||
ast_mutex_unlock(&conf->playlock);
|
||||
|
@ -7395,13 +7403,6 @@ static void sla_station_destructor(void *obj)
|
|||
ast_string_field_free_memory(station);
|
||||
}
|
||||
|
||||
static int sla_trunk_hash(const void *obj, const int flags)
|
||||
{
|
||||
const struct sla_trunk *trunk = obj;
|
||||
|
||||
return ast_str_case_hash(trunk->name);
|
||||
}
|
||||
|
||||
static int sla_trunk_cmp(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct sla_trunk *trunk = obj, *trunk2 = arg;
|
||||
|
@ -7409,13 +7410,6 @@ static int sla_trunk_cmp(void *obj, void *arg, int flags)
|
|||
return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
|
||||
}
|
||||
|
||||
static int sla_station_hash(const void *obj, const int flags)
|
||||
{
|
||||
const struct sla_station *station = obj;
|
||||
|
||||
return ast_str_case_hash(station->name);
|
||||
}
|
||||
|
||||
static int sla_station_cmp(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct sla_station *station = obj, *station2 = arg;
|
||||
|
@ -7869,8 +7863,10 @@ static int sla_load_config(int reload)
|
|||
if (!reload) {
|
||||
ast_mutex_init(&sla.lock);
|
||||
ast_cond_init(&sla.cond, NULL);
|
||||
sla_trunks = ao2_container_alloc(1, sla_trunk_hash, sla_trunk_cmp);
|
||||
sla_stations = ao2_container_alloc(1, sla_station_hash, sla_station_cmp);
|
||||
sla_trunks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
NULL, sla_trunk_cmp);
|
||||
sla_stations = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
NULL, sla_station_cmp);
|
||||
}
|
||||
|
||||
if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
|
||||
|
|
|
@ -164,6 +164,7 @@
|
|||
#include "asterisk/say.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/cli.h"
|
||||
|
|
|
@ -115,6 +115,11 @@
|
|||
Like with the basic filename argument, if an absolute path isn't given, it will create
|
||||
the file in the configured monitoring directory.</para>
|
||||
</option>
|
||||
<option name="S">
|
||||
<para>When combined with the <replaceable>r</replaceable> or <replaceable>t</replaceable>
|
||||
option, inserts silence when necessary to maintain synchronization between the receive
|
||||
and transmit audio streams.</para>
|
||||
</option>
|
||||
<option name="i">
|
||||
<argument name="chanvar" required="true" />
|
||||
<para>Stores the MixMonitor's ID on this channel variable.</para>
|
||||
|
@ -347,7 +352,8 @@ enum mixmonitor_flags {
|
|||
MUXFLAG_VMRECIPIENTS = (1 << 10),
|
||||
MUXFLAG_BEEP = (1 << 11),
|
||||
MUXFLAG_BEEP_START = (1 << 12),
|
||||
MUXFLAG_BEEP_STOP = (1 << 13)
|
||||
MUXFLAG_BEEP_STOP = (1 << 13),
|
||||
MUXFLAG_RWSYNC = (1 << 14),
|
||||
};
|
||||
|
||||
enum mixmonitor_args {
|
||||
|
@ -359,6 +365,7 @@ enum mixmonitor_args {
|
|||
OPT_ARG_UID,
|
||||
OPT_ARG_VMRECIPIENTS,
|
||||
OPT_ARG_BEEP_INTERVAL,
|
||||
OPT_ARG_RWSYNC,
|
||||
OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
|
||||
};
|
||||
|
||||
|
@ -375,6 +382,7 @@ AST_APP_OPTIONS(mixmonitor_opts, {
|
|||
AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
|
||||
AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
|
||||
AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
|
||||
AST_APP_OPTION_ARG('S', MUXFLAG_RWSYNC, OPT_ARG_RWSYNC),
|
||||
});
|
||||
|
||||
struct mixmonitor_ds {
|
||||
|
@ -962,6 +970,9 @@ static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
|
|||
}
|
||||
|
||||
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
|
||||
if ((ast_test_flag(mixmonitor, MUXFLAG_RWSYNC))) {
|
||||
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_SUBSTITUTE_SILENCE);
|
||||
}
|
||||
|
||||
if (readvol)
|
||||
mixmonitor->audiohook.options.read_volume = readvol;
|
||||
|
|
|
@ -440,4 +440,9 @@ static int load_module(void)
|
|||
return ast_register_application_xml(app_page, page_exec);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Page Multiple Phones");
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Page Multiple Phones",
|
||||
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.requires = "app_confbridge",
|
||||
);
|
||||
|
|
254
apps/app_queue.c
254
apps/app_queue.c
|
@ -169,21 +169,15 @@
|
|||
<argument name="priority" required="true" />
|
||||
<para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
|
||||
to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
|
||||
<note>
|
||||
<para>Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
</note>
|
||||
<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>
|
||||
<note>
|
||||
<para>Any channel variables you want the called channel to inherit from the caller channel must be
|
||||
prefixed with one or two underbars ('_').</para>
|
||||
</note>
|
||||
<note>
|
||||
<para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
|
||||
</note>
|
||||
<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">
|
||||
<para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
|
||||
|
@ -256,12 +250,12 @@
|
|||
</parameter>
|
||||
<parameter name="macro">
|
||||
<para>Will run a macro on the called party's channel (the queue member) once the parties are connected.</para>
|
||||
<note>
|
||||
<para>Macros are deprecated, GoSub should be used instead.</para>
|
||||
</note>
|
||||
<para>NOTE: Macros are deprecated, GoSub should be used instead.</para>
|
||||
</parameter>
|
||||
<parameter name="gosub">
|
||||
<para>Will run a gosub on the called party's channel (the queue member) once the parties are connected.</para>
|
||||
<para>Will run a gosub on the called party's channel (the queue member)
|
||||
once the parties are connected. The subroutine execution starts in the
|
||||
named context at the s exten and priority 1.</para>
|
||||
</parameter>
|
||||
<parameter name="rule">
|
||||
<para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
|
||||
|
@ -325,6 +319,7 @@
|
|||
<parameter name="options" />
|
||||
<parameter name="membername" />
|
||||
<parameter name="stateinterface" />
|
||||
<parameter name="wrapuptime" />
|
||||
</syntax>
|
||||
<description>
|
||||
<para>Dynamically adds interface to an existing queue. If the interface is
|
||||
|
@ -588,7 +583,8 @@
|
|||
</function>
|
||||
<function name="QUEUE_MEMBER" language="en_US">
|
||||
<synopsis>
|
||||
Count number of members answering a queue.
|
||||
Provides a count of queue members based on the provided criteria, or updates a
|
||||
queue member's settings.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<parameter name="queuename" required="false" />
|
||||
|
@ -1114,6 +1110,9 @@
|
|||
<enum name="1"/>
|
||||
</enumlist>
|
||||
</parameter>
|
||||
<parameter name="Wrapuptime">
|
||||
<para>The Wrapup Time of the queue member. If this value is set will override the wrapup time of queue.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
</managerEventInstance>
|
||||
</managerEvent>
|
||||
|
@ -1924,27 +1923,13 @@ static void queue_member_follower_removal(struct call_queue *queue, struct membe
|
|||
ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
|
||||
}
|
||||
|
||||
#define queue_ref(q) _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define queue_unref(q) _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define queue_t_ref(q, tag) _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define queue_t_unref(q, tag) _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#define queue_ref(q) ao2_bump(q)
|
||||
#define queue_unref(q) ({ ao2_cleanup(q); NULL; })
|
||||
#define queue_t_ref(q, tag) ao2_t_bump(q, tag)
|
||||
#define queue_t_unref(q, tag) ({ ao2_t_cleanup(q, tag); NULL; })
|
||||
#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
|
||||
#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
|
||||
|
||||
static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
|
||||
{
|
||||
__ao2_ref(q, 1, tag, file, line, filename);
|
||||
return q;
|
||||
}
|
||||
|
||||
static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
|
||||
{
|
||||
if (q) {
|
||||
__ao2_ref(q, -1, tag, file, line, filename);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! \brief Set variables of queue */
|
||||
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
|
||||
{
|
||||
|
@ -2203,7 +2188,12 @@ static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic
|
|||
return;
|
||||
}
|
||||
|
||||
ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
|
||||
if (caller_snapshot) {
|
||||
ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
|
||||
} else {
|
||||
ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
|
||||
}
|
||||
|
||||
if (agent_snapshot) {
|
||||
ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
|
||||
}
|
||||
|
@ -2255,6 +2245,7 @@ static void queue_publish_member_blob(struct stasis_message_type *type, struct a
|
|||
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
|
||||
|
||||
if (!blob || !type) {
|
||||
ast_json_unref(blob);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2274,7 +2265,7 @@ static void queue_publish_member_blob(struct stasis_message_type *type, struct a
|
|||
|
||||
static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
|
||||
{
|
||||
return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i}",
|
||||
return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
|
||||
"Queue", q->name,
|
||||
"MemberName", mem->membername,
|
||||
"Interface", mem->interface,
|
||||
|
@ -2288,7 +2279,8 @@ static struct ast_json *queue_member_blob_create(struct call_queue *q, struct me
|
|||
"Status", mem->status,
|
||||
"Paused", mem->paused,
|
||||
"PausedReason", mem->reason_paused,
|
||||
"Ringinuse", mem->ringinuse);
|
||||
"Ringinuse", mem->ringinuse,
|
||||
"Wrapuptime", mem->wrapuptime);
|
||||
}
|
||||
|
||||
/*! \brief Check if members are available
|
||||
|
@ -2693,7 +2685,7 @@ static void destroy_queue_member_cb(void *obj)
|
|||
}
|
||||
|
||||
/*! \brief allocate space for new queue member and set fields based on parameters passed */
|
||||
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
|
||||
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
|
||||
{
|
||||
struct member *cur;
|
||||
|
||||
|
@ -2701,6 +2693,7 @@ static struct member *create_queue_member(const char *interface, const char *mem
|
|||
cur->ringinuse = ringinuse;
|
||||
cur->penalty = penalty;
|
||||
cur->paused = paused;
|
||||
cur->wrapuptime = wrapuptime;
|
||||
if (paused) {
|
||||
time(&cur->lastpause); /* Update time of last pause */
|
||||
}
|
||||
|
@ -2819,10 +2812,11 @@ static void init_queue(struct call_queue *q)
|
|||
q->autopausedelay = 0;
|
||||
if (!q->members) {
|
||||
if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
|
||||
/* linear strategy depends on order, so we have to place all members in a single bucket */
|
||||
q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
|
||||
/* linear strategy depends on order, so we have to place all members in a list */
|
||||
q->members = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, member_cmp_fn);
|
||||
} else {
|
||||
q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
|
||||
q->members = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
|
||||
member_hash_fn, NULL, member_cmp_fn);
|
||||
}
|
||||
}
|
||||
q->found = 1;
|
||||
|
@ -3417,7 +3411,14 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
|
||||
|
||||
if (ast_strlen_zero(rt_uniqueid)) {
|
||||
ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
|
||||
ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
|
||||
S_OR(membername, "NULL"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(interface)) {
|
||||
ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
|
||||
S_OR(membername, "NULL"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3462,6 +3463,9 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
|
||||
if (paused_str) {
|
||||
m->paused = paused;
|
||||
if (paused) {
|
||||
time(&m->lastpause); /* XXX: Should this come from realtime? */
|
||||
}
|
||||
ast_devstate_changed(m->paused ? QUEUE_PAUSED_DEVSTATE : QUEUE_UNPAUSED_DEVSTATE,
|
||||
AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
|
||||
}
|
||||
|
@ -3481,7 +3485,7 @@ static void rt_handle_member_record(struct call_queue *q, char *category, struct
|
|||
|
||||
/* Create a new member */
|
||||
if (!found) {
|
||||
if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse))) {
|
||||
if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
|
||||
m->dead = 0;
|
||||
m->realtime = 1;
|
||||
ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
|
||||
|
@ -4497,6 +4501,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
char tech[256];
|
||||
char *location;
|
||||
const char *macrocontext, *macroexten;
|
||||
struct ast_format_cap *nativeformats;
|
||||
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
|
||||
|
||||
/* on entry here, we know that tmp->chan == NULL */
|
||||
|
@ -4513,8 +4518,13 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
location = "";
|
||||
}
|
||||
|
||||
ast_channel_lock(qe->chan);
|
||||
nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
|
||||
ast_channel_unlock(qe->chan);
|
||||
|
||||
/* Request the peer */
|
||||
tmp->chan = ast_request(tech, ast_channel_nativeformats(qe->chan), NULL, qe->chan, location, &status);
|
||||
tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
|
||||
ao2_cleanup(nativeformats);
|
||||
if (!tmp->chan) { /* If we can't, just go on to the next call */
|
||||
ao2_lock(qe->parent);
|
||||
qe->parent->rrpos++;
|
||||
|
@ -4680,7 +4690,7 @@ static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *bus
|
|||
/* Ring just the best channel */
|
||||
ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
|
||||
ret = ring_entry(qe, best, busies);
|
||||
if (qe->predial_callee && cur->chan) {
|
||||
if (qe->predial_callee && best->chan) {
|
||||
ast_autoservice_start(best->chan);
|
||||
}
|
||||
}
|
||||
|
@ -5434,12 +5444,20 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
|
|||
case AST_FRAME_CONTROL:
|
||||
switch (f->subclass.integer) {
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
if (o->block_connected_update) {
|
||||
ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_REDIRECTING:
|
||||
if (o->block_connected_update) {
|
||||
ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
|
||||
break;
|
||||
}
|
||||
if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
|
||||
ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
|
@ -5880,12 +5898,12 @@ static void send_agent_complete(const char *queuename, struct ast_channel_snapsh
|
|||
break;
|
||||
}
|
||||
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i, s: s}",
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
|
||||
"Queue", queuename,
|
||||
"Interface", member->interface,
|
||||
"MemberName", member->membername,
|
||||
"HoldTime", (long)(callstart - holdstart),
|
||||
"TalkTime", (long)(time(NULL) - callstart),
|
||||
"HoldTime", (ast_json_int_t)(callstart - holdstart),
|
||||
"TalkTime", (ast_json_int_t)(time(NULL) - callstart),
|
||||
"Reason", reason ?: "");
|
||||
|
||||
queue_publish_multi_channel_snapshot_blob(ast_queue_topic(queuename), caller, peer,
|
||||
|
@ -5985,10 +6003,6 @@ struct queue_stasis_data {
|
|||
struct local_optimization caller_optimize;
|
||||
/*! Local channel optimization details for the member */
|
||||
struct local_optimization member_optimize;
|
||||
/*! Member channel */
|
||||
struct ast_channel *member_channel;
|
||||
/*! Caller channel */
|
||||
struct ast_channel *caller_channel;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -6006,9 +6020,6 @@ static void queue_stasis_data_destructor(void *obj)
|
|||
ao2_cleanup(queue_data->member);
|
||||
queue_unref(queue_data->queue);
|
||||
ast_string_field_free_memory(queue_data);
|
||||
|
||||
ao2_ref(queue_data->member_channel, -1);
|
||||
ao2_ref(queue_data->caller_channel, -1);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -6056,15 +6067,6 @@ static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
|
|||
ao2_ref(mem, +1);
|
||||
queue_data->member = mem;
|
||||
|
||||
/*
|
||||
* During transfers it's possible for both the member and/or caller
|
||||
* channel(s) to not be available. Adding a reference here ensures
|
||||
* that the channels remain until app_queue is completely done with
|
||||
* them.
|
||||
*/
|
||||
queue_data->member_channel = ao2_bump(peer);
|
||||
queue_data->caller_channel = ao2_bump(qe->chan);
|
||||
|
||||
return queue_data;
|
||||
}
|
||||
|
||||
|
@ -6076,10 +6078,9 @@ static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe,
|
|||
* attended transfer was completed.
|
||||
*
|
||||
* \param queue_data Data pertaining to the particular call in the queue.
|
||||
* \param caller The channel snapshot for the caller channel in the queue.
|
||||
* \param atxfer_msg The stasis attended transfer message data.
|
||||
*/
|
||||
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_channel_snapshot *caller,
|
||||
static void log_attended_transfer(struct queue_stasis_data *queue_data,
|
||||
struct ast_attended_transfer_message *atxfer_msg)
|
||||
{
|
||||
RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
|
||||
|
@ -6108,7 +6109,7 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
|
|||
return;
|
||||
}
|
||||
|
||||
ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
|
||||
ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
|
||||
ast_str_buffer(transfer_str),
|
||||
(long) (queue_data->starttime - queue_data->holdstart),
|
||||
(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
|
||||
|
@ -6196,7 +6197,7 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su
|
|||
context = transfer_msg->context;
|
||||
|
||||
ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
|
||||
ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
|
||||
ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
|
||||
"BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
|
||||
exten, context,
|
||||
(long) (queue_data->starttime - queue_data->holdstart),
|
||||
|
@ -6259,8 +6260,7 @@ static void handle_attended_transfer(void *userdata, struct stasis_subscription
|
|||
ao2_unlock(queue_data);
|
||||
|
||||
ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
|
||||
|
||||
log_attended_transfer(queue_data, caller_snapshot, atxfer_msg);
|
||||
log_attended_transfer(queue_data, atxfer_msg);
|
||||
|
||||
send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
|
||||
queue_data->holdstart, queue_data->starttime, TRANSFER);
|
||||
|
@ -6458,7 +6458,7 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
|
|||
ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
|
||||
channel_blob->snapshot->name);
|
||||
|
||||
ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
|
||||
ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
|
||||
reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
|
||||
(long) (queue_data->starttime - queue_data->holdstart),
|
||||
(long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
|
||||
|
@ -6987,6 +6987,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
|
||||
ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
|
||||
ast_autoservice_chan_hangup_peer(qe->chan, peer);
|
||||
pending_members_remove(member);
|
||||
ao2_ref(member, -1);
|
||||
goto out;
|
||||
} else if (ast_check_hangup(qe->chan)) {
|
||||
|
@ -6997,6 +6998,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
qe->handled = -1;
|
||||
ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
|
||||
ast_autoservice_chan_hangup_peer(qe->chan, peer);
|
||||
pending_members_remove(member);
|
||||
ao2_ref(member, -1);
|
||||
return -1;
|
||||
}
|
||||
|
@ -7016,6 +7018,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
record_abandoned(qe);
|
||||
ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
|
||||
ast_autoservice_chan_hangup_peer(qe->chan, peer);
|
||||
pending_members_remove(member);
|
||||
ao2_ref(member, -1);
|
||||
return -1;
|
||||
}
|
||||
|
@ -7171,12 +7174,12 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
|
|||
ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
|
||||
(long)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: i, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
|
||||
"Queue", queuename,
|
||||
"Interface", member->interface,
|
||||
"MemberName", member->membername,
|
||||
"HoldTime", (long) (time(NULL) - qe->start),
|
||||
"RingTime", (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
"HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
|
||||
"RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
|
||||
queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
|
||||
|
||||
ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
|
||||
|
@ -7280,14 +7283,15 @@ static void dump_queue_members(struct call_queue *pm_queue)
|
|||
continue;
|
||||
}
|
||||
|
||||
ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s",
|
||||
ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
|
||||
ast_str_strlen(value) ? "|" : "",
|
||||
cur_member->interface,
|
||||
cur_member->penalty,
|
||||
cur_member->paused,
|
||||
cur_member->membername,
|
||||
cur_member->state_interface,
|
||||
cur_member->reason_paused);
|
||||
cur_member->reason_paused,
|
||||
cur_member->wrapuptime);
|
||||
|
||||
ao2_ref(cur_member, -1);
|
||||
}
|
||||
|
@ -7364,7 +7368,7 @@ static int remove_from_queue(const char *queuename, const char *interface)
|
|||
* \retval RES_EXISTS queue exists but no members
|
||||
* \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
|
||||
*/
|
||||
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused)
|
||||
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
|
||||
{
|
||||
struct call_queue *q;
|
||||
struct member *new_member, *old_member;
|
||||
|
@ -7378,7 +7382,7 @@ static int add_to_queue(const char *queuename, const char *interface, const char
|
|||
|
||||
ao2_lock(q);
|
||||
if ((old_member = interface_exists(q, interface)) == NULL) {
|
||||
if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) {
|
||||
if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse, wrapuptime))) {
|
||||
new_member->dynamic = 1;
|
||||
if (reason_paused) {
|
||||
ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
|
||||
|
@ -7770,6 +7774,8 @@ static void reload_queue_members(void)
|
|||
int penalty = 0;
|
||||
char *paused_tok;
|
||||
int paused = 0;
|
||||
char *wrapuptime_tok;
|
||||
int wrapuptime = 0;
|
||||
char *reason_paused;
|
||||
struct ast_db_entry *db_tree;
|
||||
struct ast_db_entry *entry;
|
||||
|
@ -7818,6 +7824,7 @@ static void reload_queue_members(void)
|
|||
membername = strsep(&member, ";");
|
||||
state_interface = strsep(&member, ";");
|
||||
reason_paused = strsep(&member, ";");
|
||||
wrapuptime_tok = strsep(&member, ";");
|
||||
|
||||
if (!penalty_tok) {
|
||||
ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
|
||||
|
@ -7839,10 +7846,18 @@ static void reload_queue_members(void)
|
|||
break;
|
||||
}
|
||||
|
||||
ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s\n",
|
||||
queue_name, interface, membername, penalty, paused, reason_paused);
|
||||
if (!ast_strlen_zero(wrapuptime_tok)) {
|
||||
wrapuptime = strtol(wrapuptime_tok, NULL, 10);
|
||||
if (errno == ERANGE) {
|
||||
ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused) == RES_OUTOFMEMORY) {
|
||||
ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
|
||||
queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
|
||||
|
||||
if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
|
||||
ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
|
||||
break;
|
||||
}
|
||||
|
@ -8004,7 +8019,7 @@ static int rqm_exec(struct ast_channel *chan, const char *data)
|
|||
static int aqm_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
int res=-1;
|
||||
char *parse, *temppos = NULL;
|
||||
char *parse, *tmp, *temppos = NULL;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(queuename);
|
||||
AST_APP_ARG(interface);
|
||||
|
@ -8012,11 +8027,13 @@ static int aqm_exec(struct ast_channel *chan, const char *data)
|
|||
AST_APP_ARG(options);
|
||||
AST_APP_ARG(membername);
|
||||
AST_APP_ARG(state_interface);
|
||||
AST_APP_ARG(wrapuptime);
|
||||
);
|
||||
int penalty = 0;
|
||||
int wrapuptime;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
|
||||
ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -8039,7 +8056,18 @@ static int aqm_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
}
|
||||
|
||||
switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL)) {
|
||||
if (!ast_strlen_zero(args.wrapuptime)) {
|
||||
tmp = args.wrapuptime;
|
||||
ast_strip(tmp);
|
||||
wrapuptime = atoi(tmp);
|
||||
if (wrapuptime < 0) {
|
||||
wrapuptime = 0;
|
||||
}
|
||||
} else {
|
||||
wrapuptime = 0;
|
||||
}
|
||||
|
||||
switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface, NULL, wrapuptime)) {
|
||||
case RES_OKAY:
|
||||
if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
|
||||
ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
|
||||
|
@ -8444,14 +8472,15 @@ check_turns:
|
|||
break;
|
||||
}
|
||||
|
||||
/* If using dynamic realtime members, we should regenerate the member list for this queue */
|
||||
update_realtime_members(qe.parent);
|
||||
/* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
|
||||
res = wait_a_bit(&qe);
|
||||
if (res) {
|
||||
goto stop;
|
||||
}
|
||||
|
||||
/* If using dynamic realtime members, we should regenerate the member list for this queue */
|
||||
update_realtime_members(qe.parent);
|
||||
|
||||
/* Since this is a priority queue and
|
||||
* it is not sure that we are still at the head
|
||||
* of the queue, go and check for our turn again.
|
||||
|
@ -8471,12 +8500,12 @@ stop:
|
|||
"%d|%d|%ld", qe.pos, qe.opos,
|
||||
(long) (time(NULL) - qe.start));
|
||||
res = -1;
|
||||
} else if (qcontinue) {
|
||||
reason = QUEUE_CONTINUE;
|
||||
res = 0;
|
||||
} else if (reason == QUEUE_LEAVEEMPTY) {
|
||||
/* Return back to dialplan, don't hang up */
|
||||
res = 0;
|
||||
} else if (qcontinue) {
|
||||
reason = QUEUE_CONTINUE;
|
||||
res = 0;
|
||||
}
|
||||
} else if (qe.valid_digits) {
|
||||
ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
|
||||
|
@ -9284,7 +9313,7 @@ static void reload_single_member(const char *memberdata, struct call_queue *q)
|
|||
ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
|
||||
cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
|
||||
|
||||
if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse))) {
|
||||
if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse, wrapuptime))) {
|
||||
newm->wrapuptime = wrapuptime;
|
||||
if (cur) {
|
||||
/* Round Robin Queue Position must be copied if this is replacing an existing member */
|
||||
|
@ -9723,14 +9752,14 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||
mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
|
||||
mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
|
||||
mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
|
||||
|
||||
if (mem->paused) {
|
||||
if (ast_strlen_zero(mem->reason_paused)) {
|
||||
ast_str_append(&out, 0, " %s(paused was %ld secs ago)%s",
|
||||
ast_term_color(COLOR_BROWN, COLOR_BLACK), (long) (time(NULL) - mem->lastpause), ast_term_reset());
|
||||
} else {
|
||||
ast_str_append(&out, 0, " %s(paused:%s was %ld secs ago)%s", ast_term_color(COLOR_BROWN, COLOR_BLACK),
|
||||
mem->reason_paused, (long) (time(NULL) - mem->lastcall), ast_term_reset());
|
||||
}
|
||||
ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
|
||||
ast_term_color(COLOR_BROWN, COLOR_BLACK),
|
||||
ast_strlen_zero(mem->reason_paused) ? "" : ":",
|
||||
ast_strlen_zero(mem->reason_paused) ? "" : mem->reason_paused,
|
||||
(long) (now - mem->lastpause),
|
||||
ast_term_reset());
|
||||
}
|
||||
|
||||
ast_str_append(&out, 0, " (%s%s%s)",
|
||||
|
@ -9740,7 +9769,7 @@ static char *__queues_show(struct mansession *s, int fd, int argc, const char *
|
|||
ast_devstate2str(mem->status), ast_term_reset());
|
||||
if (mem->calls) {
|
||||
ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
|
||||
mem->calls, (long) (time(NULL) - mem->lastcall));
|
||||
mem->calls, (long) (now - mem->lastcall));
|
||||
} else {
|
||||
ast_str_append(&out, 0, " has taken no calls yet");
|
||||
}
|
||||
|
@ -10097,11 +10126,12 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
|
|||
"Status: %d\r\n"
|
||||
"Paused: %d\r\n"
|
||||
"PausedReason: %s\r\n"
|
||||
"Wrapuptime: %d\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
|
||||
mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, mem->starttime ? 1 : 0, mem->status,
|
||||
mem->paused, mem->reason_paused, idText);
|
||||
mem->paused, mem->reason_paused, mem->wrapuptime, idText);
|
||||
++q_items;
|
||||
}
|
||||
ao2_ref(mem, -1);
|
||||
|
@ -10146,8 +10176,8 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
|
|||
|
||||
static int manager_add_queue_member(struct mansession *s, const struct message *m)
|
||||
{
|
||||
const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
|
||||
int paused, penalty = 0;
|
||||
const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface, *wrapuptime_s;
|
||||
int paused, penalty, wrapuptime = 0;
|
||||
|
||||
queuename = astman_get_header(m, "Queue");
|
||||
interface = astman_get_header(m, "Interface");
|
||||
|
@ -10155,6 +10185,7 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
|
|||
paused_s = astman_get_header(m, "Paused");
|
||||
membername = astman_get_header(m, "MemberName");
|
||||
state_interface = astman_get_header(m, "StateInterface");
|
||||
wrapuptime_s = astman_get_header(m, "Wrapuptime");
|
||||
|
||||
if (ast_strlen_zero(queuename)) {
|
||||
astman_send_error(s, m, "'Queue' not specified.");
|
||||
|
@ -10172,13 +10203,19 @@ static int manager_add_queue_member(struct mansession *s, const struct message *
|
|||
penalty = 0;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(wrapuptime_s)) {
|
||||
wrapuptime = 0;
|
||||
} else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
|
||||
wrapuptime = 0;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(paused_s)) {
|
||||
paused = 0;
|
||||
} else {
|
||||
paused = abs(ast_true(paused_s));
|
||||
}
|
||||
|
||||
switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL)) {
|
||||
switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, NULL, wrapuptime)) {
|
||||
case RES_OKAY:
|
||||
if (ast_strlen_zero(membername) || !log_membername_as_agent) {
|
||||
ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
|
||||
|
@ -10354,7 +10391,7 @@ static char *complete_queue_add_member(const char *line, const char *word, int p
|
|||
case 6: /* only one possible match, "penalty" */
|
||||
return state == 0 ? ast_strdup("penalty") : NULL;
|
||||
case 7:
|
||||
if (state < 100) { /* 0-99 */
|
||||
if (0 <= state && state < 100) { /* 0-99 */
|
||||
char *num;
|
||||
if ((num = ast_malloc(3))) {
|
||||
sprintf(num, "%d", state);
|
||||
|
@ -10528,7 +10565,7 @@ static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct as
|
|||
state_interface = a->argv[11];
|
||||
}
|
||||
|
||||
switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL)) {
|
||||
switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface, NULL, 0)) {
|
||||
case RES_OKAY:
|
||||
if (ast_strlen_zero(membername) || !log_membername_as_agent) {
|
||||
ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
|
||||
|
@ -11247,13 +11284,14 @@ static int load_module(void)
|
|||
struct stasis_topic *queue_topic;
|
||||
struct stasis_topic *manager_topic;
|
||||
|
||||
queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
|
||||
queues = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_QUEUE_BUCKETS,
|
||||
queue_hash_cb, NULL, queue_cmp_cb);
|
||||
if (!queues) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
pending_members = ao2_container_alloc(
|
||||
MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, pending_members_cmp);
|
||||
pending_members = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, NULL, pending_members_cmp);
|
||||
if (!pending_members) {
|
||||
unload_module();
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
|
@ -11329,6 +11367,8 @@ static int load_module(void)
|
|||
if (!device_state_sub) {
|
||||
err = -1;
|
||||
}
|
||||
stasis_subscription_accept_message_type(device_state_sub, ast_device_state_message_type());
|
||||
stasis_subscription_set_filter(device_state_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
|
||||
manager_topic = ast_manager_get_topic();
|
||||
queue_topic = ast_queue_topic_all();
|
||||
|
|
|
@ -63,6 +63,10 @@
|
|||
<option name="n">
|
||||
<para>Read digits even if the channel is not answered.</para>
|
||||
</option>
|
||||
<option name="p">
|
||||
<para>The extension entered will be considered complete when a <literal>#</literal>
|
||||
is entered.</para>
|
||||
</option>
|
||||
</optionlist>
|
||||
</parameter>
|
||||
<parameter name="timeout">
|
||||
|
@ -100,12 +104,14 @@ enum readexten_option_flags {
|
|||
OPT_SKIP = (1 << 0),
|
||||
OPT_INDICATION = (1 << 1),
|
||||
OPT_NOANSWER = (1 << 2),
|
||||
OPT_POUND_TO_END = (1 << 3),
|
||||
};
|
||||
|
||||
AST_APP_OPTIONS(readexten_app_options, {
|
||||
AST_APP_OPTION('s', OPT_SKIP),
|
||||
AST_APP_OPTION('i', OPT_INDICATION),
|
||||
AST_APP_OPTION('n', OPT_NOANSWER),
|
||||
AST_APP_OPTION('p', OPT_POUND_TO_END),
|
||||
});
|
||||
|
||||
static char *app = "ReadExten";
|
||||
|
@ -226,6 +232,11 @@ static int readexten_exec(struct ast_channel *chan, const char *data)
|
|||
break;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, OPT_POUND_TO_END) && res == '#') {
|
||||
exten[x] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
exten[x] = res;
|
||||
if (!ast_matchmore_extension(chan, arglist.context, exten, 1 /* priority */,
|
||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
|
||||
|
|
|
@ -580,7 +580,9 @@ static void *skel_config_alloc(void)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (!(cfg->levels = ao2_container_alloc(LEVEL_BUCKETS, skel_level_hash, skel_level_cmp))) {
|
||||
cfg->levels = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, LEVEL_BUCKETS,
|
||||
skel_level_hash, NULL, skel_level_cmp);
|
||||
if (!cfg->levels) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -725,7 +727,9 @@ static int load_module(void)
|
|||
if (aco_info_init(&cfg_info)) {
|
||||
goto error;
|
||||
}
|
||||
if (!(games = ao2_container_alloc(1, NULL, NULL))) {
|
||||
|
||||
games = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
|
||||
if (!games) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@
|
|||
#include "asterisk/module.h"
|
||||
#include "asterisk/adsi.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/localtime.h"
|
||||
|
@ -810,11 +811,16 @@ struct baseio {
|
|||
unsigned char iobuf[BASEMAXINLINE];
|
||||
};
|
||||
|
||||
#define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
|
||||
#define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
|
||||
/* MAX_VM_MAILBOX_LEN allows enough room for the '@' and NULL terminator */
|
||||
#define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
|
||||
|
||||
/*! Structure for linked list of users
|
||||
* Use ast_vm_user_destroy() to free one of these structures. */
|
||||
struct ast_vm_user {
|
||||
char context[AST_MAX_CONTEXT]; /*!< Voicemail context */
|
||||
char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
|
||||
char context[MAX_VM_CONTEXT_LEN];/*!< Voicemail context */
|
||||
char mailbox[MAX_VM_MBOX_ID_LEN];/*!< Mailbox id, unique within vm context */
|
||||
char password[80]; /*!< Secret pin code, numbers only */
|
||||
char fullname[80]; /*!< Full name, for directory app */
|
||||
char *email; /*!< E-mail address */
|
||||
|
@ -994,6 +1000,7 @@ static int skipms;
|
|||
static int maxlogins;
|
||||
static int minpassword;
|
||||
static int passwordlocation;
|
||||
static char aliasescontext[MAX_VM_CONTEXT_LEN];
|
||||
|
||||
/*! Poll mailboxes for changes since there is something external to
|
||||
* app_voicemail that may change them. */
|
||||
|
@ -1046,6 +1053,27 @@ static struct ast_taskprocessor *mwi_subscription_tps;
|
|||
|
||||
static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
|
||||
|
||||
struct alias_mailbox_mapping {
|
||||
char *alias;
|
||||
char *mailbox;
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
struct mailbox_alias_mapping {
|
||||
char *alias;
|
||||
char *mailbox;
|
||||
char buf[0];
|
||||
};
|
||||
|
||||
#define MAPPING_BUCKETS 511
|
||||
static struct ao2_container *alias_mailbox_mappings;
|
||||
AO2_STRING_FIELD_HASH_FN(alias_mailbox_mapping, alias);
|
||||
AO2_STRING_FIELD_CMP_FN(alias_mailbox_mapping, alias);
|
||||
|
||||
static struct ao2_container *mailbox_alias_mappings;
|
||||
AO2_STRING_FIELD_HASH_FN(mailbox_alias_mapping, mailbox);
|
||||
AO2_STRING_FIELD_CMP_FN(mailbox_alias_mapping, mailbox);
|
||||
|
||||
/* custom audio control prompts for voicemail playback */
|
||||
static char listen_control_forward_key[12];
|
||||
static char listen_control_reverse_key[12];
|
||||
|
@ -1760,9 +1788,31 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *contex
|
|||
ast_set2_flag(vmu, !ivm, VM_ALLOCED);
|
||||
AST_LIST_NEXT(vmu, list) = NULL;
|
||||
}
|
||||
} else
|
||||
vmu = find_user_realtime(ivm, context, mailbox);
|
||||
}
|
||||
AST_LIST_UNLOCK(&users);
|
||||
if (!vmu) {
|
||||
vmu = find_user_realtime(ivm, context, mailbox);
|
||||
}
|
||||
if (!vmu && !ast_strlen_zero(aliasescontext)) {
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
char *search_string = ast_alloca(MAX_VM_MAILBOX_LEN);
|
||||
|
||||
snprintf(search_string, MAX_VM_MAILBOX_LEN, "%s%s%s",
|
||||
mailbox,
|
||||
ast_strlen_zero(context) ? "" : "@",
|
||||
S_OR(context, ""));
|
||||
|
||||
mapping = ao2_find(alias_mailbox_mappings, search_string, OBJ_SEARCH_KEY);
|
||||
if (mapping) {
|
||||
char *search_mailbox = NULL;
|
||||
char *search_context = NULL;
|
||||
|
||||
separate_mailbox(ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);
|
||||
ao2_ref(mapping, -1);
|
||||
vmu = find_user(ivm, search_mailbox, search_context);
|
||||
}
|
||||
}
|
||||
|
||||
return vmu;
|
||||
}
|
||||
|
||||
|
@ -2050,6 +2100,19 @@ static void free_user(struct ast_vm_user *vmu)
|
|||
}
|
||||
}
|
||||
|
||||
static void free_user_final(struct ast_vm_user *vmu)
|
||||
{
|
||||
if (!vmu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(vmu->mailbox)) {
|
||||
ast_delete_mwi_state_full(vmu->mailbox, vmu->context, NULL);
|
||||
}
|
||||
|
||||
free_user(vmu);
|
||||
}
|
||||
|
||||
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
|
||||
|
||||
int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
|
||||
|
@ -3750,6 +3813,54 @@ static void check_quota(struct vm_state *vms, char *mailbox) {
|
|||
|
||||
#endif /* IMAP_STORAGE */
|
||||
|
||||
static void cleanup_orphaned_lock_files(const char *base)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
|
||||
dir = opendir(base);
|
||||
if (!dir) {
|
||||
/* Don't complain about this too loudly */
|
||||
ast_debug(2, "Unable to open `%s': %s\n", base, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while ((e = readdir(dir))) {
|
||||
char *fullpath;
|
||||
struct stat s;
|
||||
|
||||
/* Always skip . and .. */
|
||||
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build up the full path (using dynamic memory because PATH_MAX is crap) */
|
||||
if (ast_asprintf(&fullpath, "%s/%s", base, e->d_name) == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (lstat(fullpath, &s) < 0) {
|
||||
ast_free(fullpath);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is exposing an implementation detail of ast_lock_path, but it makes
|
||||
* our life a bit easier */
|
||||
if (!strcmp(e->d_name, ".lock") && S_ISLNK(s.st_mode)) {
|
||||
if (!ast_unlock_path(base)) {
|
||||
ast_log(AST_LOG_NOTICE, "Cleaned up orphaned lock file: %s/.lock\n", base);
|
||||
}
|
||||
} else if (S_ISDIR(s.st_mode)) {
|
||||
/* If it is a directory, let's dive down */
|
||||
cleanup_orphaned_lock_files(fullpath);
|
||||
}
|
||||
|
||||
ast_free(fullpath);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/*! \brief Lock file path
|
||||
* only return failure if ast_lock_path returns 'timeout',
|
||||
* not if the path does not exist or any other reason
|
||||
|
@ -3793,7 +3904,7 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
|
|||
ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
|
||||
res = ast_odbc_prepare(obj, stmt, gps->sql);
|
||||
if (!SQL_SUCCEEDED(res)) {
|
||||
ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
|
@ -4316,7 +4427,7 @@ static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
|
|||
if (!ast_strlen_zero(data->category)) {
|
||||
SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
|
||||
}
|
||||
res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
|
||||
res = ast_odbc_execute_sql(obj, stmt, data->sql);
|
||||
if (!SQL_SUCCEEDED(res)) {
|
||||
ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
|
@ -6038,6 +6149,9 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
|
|||
struct dirent *de;
|
||||
char fn[256];
|
||||
int ret = 0;
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
char *c;
|
||||
char *m;
|
||||
|
||||
/* If no mailbox, return immediately */
|
||||
if (ast_strlen_zero(mailbox))
|
||||
|
@ -6048,7 +6162,21 @@ static int __has_voicemail(const char *context, const char *mailbox, const char
|
|||
if (ast_strlen_zero(context))
|
||||
context = "default";
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
|
||||
c = (char *)context;
|
||||
m = (char *)mailbox;
|
||||
|
||||
if (!ast_strlen_zero(aliasescontext)) {
|
||||
char tmp[MAX_VM_MAILBOX_LEN];
|
||||
|
||||
snprintf(tmp, MAX_VM_MAILBOX_LEN, "%s@%s", mailbox, context);
|
||||
mapping = ao2_find(alias_mailbox_mappings, tmp, OBJ_SEARCH_KEY);
|
||||
if (mapping) {
|
||||
separate_mailbox(ast_strdupa(mapping->mailbox), &m, &c);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, c, m, folder);
|
||||
|
||||
if (!(dir = opendir(fn)))
|
||||
return 0;
|
||||
|
@ -7073,6 +7201,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
|
|||
RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
|
||||
/* Notification must happen for this new message in Urgent folder, not INBOX */
|
||||
ast_copy_string(fn, dfn, sizeof(fn));
|
||||
pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
|
||||
msgnum = x;
|
||||
}
|
||||
#endif
|
||||
|
@ -7118,7 +7247,7 @@ leave_vm_out:
|
|||
#ifdef IMAP_STORAGE
|
||||
/* expunge message - use UID Expunge if supported on IMAP server*/
|
||||
ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
|
||||
if (expungeonhangup == 1) {
|
||||
if (expungeonhangup == 1 && vms->mailstream != NULL) {
|
||||
ast_mutex_lock(&vms->lock);
|
||||
#ifdef HAVE_IMAP_TK2006
|
||||
if (LEVELUIDPLUS (vms->mailstream)) {
|
||||
|
@ -8077,7 +8206,24 @@ static void queue_mwi_event(const char *channel_id, const char *box, int urgent,
|
|||
return;
|
||||
}
|
||||
|
||||
ast_debug(3, "Queueing event for mailbox %s New: %d Old: %d\n", box, new + urgent, old);
|
||||
ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
|
||||
|
||||
if (!ast_strlen_zero(aliasescontext)) {
|
||||
struct ao2_iterator *aliases;
|
||||
struct mailbox_alias_mapping *mapping;
|
||||
|
||||
aliases = ao2_find(mailbox_alias_mappings, box, OBJ_SEARCH_KEY | OBJ_MULTIPLE);
|
||||
while ((mapping = ao2_iterator_next(aliases))) {
|
||||
mailbox = NULL;
|
||||
context = NULL;
|
||||
ast_debug(3, "Found alias mapping: %s -> %s\n", mapping->alias, box);
|
||||
separate_mailbox(ast_strdupa(mapping->alias), &mailbox, &context);
|
||||
ast_publish_mwi_state_channel(mailbox, context, new + urgent, old, channel_id);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
ao2_iterator_destroy(aliases);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -12357,7 +12503,7 @@ static int append_mailbox(const char *context, const char *box, const char *data
|
|||
char *stringp;
|
||||
char *s;
|
||||
struct ast_vm_user *vmu;
|
||||
char *mailbox_full;
|
||||
char mailbox_full[MAX_VM_MAILBOX_LEN];
|
||||
int new = 0, old = 0, urgent = 0;
|
||||
char secretfn[PATH_MAX] = "";
|
||||
|
||||
|
@ -12386,8 +12532,8 @@ static int append_mailbox(const char *context, const char *box, const char *data
|
|||
if (stringp && (s = strsep(&stringp, ","))) {
|
||||
ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
|
||||
}
|
||||
if (stringp && (s = strsep(&stringp, ","))) {
|
||||
apply_options(vmu, s);
|
||||
if (stringp) {
|
||||
apply_options(vmu, stringp);
|
||||
}
|
||||
|
||||
switch (vmu->passwordlocation) {
|
||||
|
@ -12396,10 +12542,10 @@ static int append_mailbox(const char *context, const char *box, const char *data
|
|||
read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
|
||||
}
|
||||
|
||||
mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
|
||||
strcpy(mailbox_full, box);
|
||||
strcat(mailbox_full, "@");
|
||||
strcat(mailbox_full, context);
|
||||
snprintf(mailbox_full, MAX_VM_MAILBOX_LEN, "%s%s%s",
|
||||
box,
|
||||
ast_strlen_zero(context) ? "" : "@",
|
||||
context);
|
||||
|
||||
inboxcount2(mailbox_full, &urgent, &new, &old);
|
||||
#ifdef IMAP_STORAGE
|
||||
|
@ -12981,6 +13127,46 @@ static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struc
|
|||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Show a list of voicemail zones in the CLI */
|
||||
static char *handle_voicemail_show_aliases(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
struct ao2_iterator aliases;
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
|
||||
char *res = CLI_SUCCESS;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "voicemail show aliases";
|
||||
e->usage =
|
||||
"Usage: voicemail show aliases\n"
|
||||
" Lists mailbox aliases\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->argc != 3)
|
||||
return CLI_SHOWUSAGE;
|
||||
|
||||
if (ast_strlen_zero(aliasescontext)) {
|
||||
ast_cli(a->fd, "Aliases are not enabled\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "Aliases context: %s\n", aliasescontext);
|
||||
ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, "Alias", "Mailbox");
|
||||
|
||||
aliases = ao2_iterator_init(alias_mailbox_mappings, 0);
|
||||
while ((mapping = ao2_iterator_next(&aliases))) {
|
||||
ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
ao2_iterator_destroy(&aliases);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Reload voicemail configuration from the CLI */
|
||||
static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
|
@ -13007,6 +13193,7 @@ static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct as
|
|||
static struct ast_cli_entry cli_voicemail[] = {
|
||||
AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
|
||||
AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
|
||||
AST_CLI_DEFINE(handle_voicemail_show_aliases, "List mailbox aliases"),
|
||||
AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
|
||||
};
|
||||
|
||||
|
@ -13196,6 +13383,7 @@ static void mwi_unsub_event_cb(struct stasis_subscription_change *change)
|
|||
static void mwi_sub_event_cb(struct stasis_subscription_change *change)
|
||||
{
|
||||
struct mwi_sub_task *mwist;
|
||||
const char *topic;
|
||||
char *context;
|
||||
char *mailbox;
|
||||
|
||||
|
@ -13204,7 +13392,9 @@ static void mwi_sub_event_cb(struct stasis_subscription_change *change)
|
|||
return;
|
||||
}
|
||||
|
||||
if (separate_mailbox(ast_strdupa(stasis_topic_name(change->topic)), &mailbox, &context)) {
|
||||
/* The topic name is prefixed with "mwi:all/" as this is a pool topic */
|
||||
topic = stasis_topic_name(change->topic) + 8;
|
||||
if (separate_mailbox(ast_strdupa(topic), &mailbox, &context)) {
|
||||
ast_free(mwist);
|
||||
return;
|
||||
}
|
||||
|
@ -13225,7 +13415,6 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct
|
|||
if (stasis_message_type(msg) != stasis_subscription_change_type()) {
|
||||
return;
|
||||
}
|
||||
|
||||
change = stasis_message_data(msg);
|
||||
if (change->topic == ast_mwi_topic_all()) {
|
||||
return;
|
||||
|
@ -13531,7 +13720,7 @@ static void free_vm_users(void)
|
|||
AST_LIST_LOCK(&users);
|
||||
while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
|
||||
ast_set_flag(current, VM_ALLOCED);
|
||||
free_user(current);
|
||||
free_user_final(current);
|
||||
}
|
||||
AST_LIST_UNLOCK(&users);
|
||||
}
|
||||
|
@ -13643,11 +13832,98 @@ static int load_config_from_memory(int reload, struct ast_config *cfg, struct as
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct alias_mailbox_mapping *alias_mailbox_mapping_create(const char *alias, const char *mailbox)
|
||||
{
|
||||
struct alias_mailbox_mapping *mapping;
|
||||
size_t from_len = strlen(alias) + 1;
|
||||
size_t to_len = strlen(mailbox) + 1;
|
||||
|
||||
mapping = ao2_alloc(sizeof(*mapping) + from_len + to_len, NULL);
|
||||
if (!mapping) {
|
||||
return NULL;
|
||||
}
|
||||
mapping->alias = mapping->buf;
|
||||
mapping->mailbox = mapping->buf + from_len;
|
||||
strcpy(mapping->alias, alias); /* Safe */
|
||||
strcpy(mapping->mailbox, mailbox); /* Safe */
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
static void load_aliases(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
|
||||
if (ast_strlen_zero(aliasescontext)) {
|
||||
return;
|
||||
}
|
||||
var = ast_variable_browse(cfg, aliasescontext);
|
||||
while (var) {
|
||||
struct alias_mailbox_mapping *mapping = alias_mailbox_mapping_create(var->name, var->value);
|
||||
if (mapping) {
|
||||
ao2_link(alias_mailbox_mappings, mapping);
|
||||
ao2_link(mailbox_alias_mappings, mapping);
|
||||
ao2_ref(mapping, -1);
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_zonemessages(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
|
||||
var = ast_variable_browse(cfg, "zonemessages");
|
||||
while (var) {
|
||||
struct vm_zone *z;
|
||||
char *msg_format, *tzone;
|
||||
|
||||
z = ast_malloc(sizeof(*z));
|
||||
if (!z) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg_format = ast_strdupa(var->value);
|
||||
tzone = strsep(&msg_format, "|,");
|
||||
if (msg_format) {
|
||||
ast_copy_string(z->name, var->name, sizeof(z->name));
|
||||
ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
|
||||
ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
|
||||
AST_LIST_LOCK(&zones);
|
||||
AST_LIST_INSERT_HEAD(&zones, z, list);
|
||||
AST_LIST_UNLOCK(&zones);
|
||||
} else {
|
||||
ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
|
||||
ast_free(z);
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_users(struct ast_config *cfg)
|
||||
{
|
||||
struct ast_variable *var;
|
||||
char *cat = NULL;
|
||||
|
||||
while ((cat = ast_category_browse(cfg, cat))) {
|
||||
if (strcasecmp(cat, "general") == 0
|
||||
|| strcasecmp(cat, aliasescontext) == 0
|
||||
|| strcasecmp(cat, "zonemessages") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var = ast_variable_browse(cfg, cat);
|
||||
while (var) {
|
||||
append_mailbox(cat, var->name, var->value);
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
|
||||
{
|
||||
struct ast_vm_user *current;
|
||||
char *cat;
|
||||
struct ast_variable *var;
|
||||
const char *val;
|
||||
char *q, *stringp, *tmp;
|
||||
int x;
|
||||
|
@ -13676,6 +13952,10 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|||
/* Free all the zones structure */
|
||||
free_vm_zones();
|
||||
|
||||
/* Remove all aliases */
|
||||
ao2_callback(alias_mailbox_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
|
||||
ao2_callback(mailbox_alias_mappings, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
|
||||
|
||||
AST_LIST_LOCK(&users);
|
||||
|
||||
memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
|
||||
|
@ -13687,6 +13967,11 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|||
if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
|
||||
val = "default";
|
||||
ast_copy_string(userscontext, val, sizeof(userscontext));
|
||||
|
||||
aliasescontext[0] = '\0';
|
||||
val = ast_variable_retrieve(cfg, "general", "aliasescontext");
|
||||
ast_copy_string(aliasescontext, S_OR(val, ""), sizeof(aliasescontext));
|
||||
|
||||
/* Attach voice message to mail message ? */
|
||||
if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
|
||||
val = "yes";
|
||||
|
@ -14288,45 +14573,16 @@ static int actual_load_config(int reload, struct ast_config *cfg, struct ast_con
|
|||
}
|
||||
|
||||
/* load mailboxes from voicemail.conf */
|
||||
cat = ast_category_browse(cfg, NULL);
|
||||
while (cat) {
|
||||
if (strcasecmp(cat, "general")) {
|
||||
var = ast_variable_browse(cfg, cat);
|
||||
if (strcasecmp(cat, "zonemessages")) {
|
||||
/* Process mailboxes in this context */
|
||||
while (var) {
|
||||
append_mailbox(cat, var->name, var->value);
|
||||
var = var->next;
|
||||
}
|
||||
} else {
|
||||
/* Timezones in this context */
|
||||
while (var) {
|
||||
struct vm_zone *z;
|
||||
if ((z = ast_malloc(sizeof(*z)))) {
|
||||
char *msg_format, *tzone;
|
||||
msg_format = ast_strdupa(var->value);
|
||||
tzone = strsep(&msg_format, "|,");
|
||||
if (msg_format) {
|
||||
ast_copy_string(z->name, var->name, sizeof(z->name));
|
||||
ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
|
||||
ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
|
||||
AST_LIST_LOCK(&zones);
|
||||
AST_LIST_INSERT_HEAD(&zones, z, list);
|
||||
AST_LIST_UNLOCK(&zones);
|
||||
} else {
|
||||
ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
|
||||
ast_free(z);
|
||||
}
|
||||
} else {
|
||||
AST_LIST_UNLOCK(&users);
|
||||
return -1;
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
cat = ast_category_browse(cfg, cat);
|
||||
}
|
||||
|
||||
/*
|
||||
* Aliases must be loaded before users or the aliases won't be notified
|
||||
* if there's existing voicemail in the user mailbox.
|
||||
*/
|
||||
load_aliases(cfg);
|
||||
|
||||
load_zonemessages(cfg);
|
||||
|
||||
load_users(cfg);
|
||||
|
||||
AST_LIST_UNLOCK(&users);
|
||||
|
||||
|
@ -15077,6 +15333,16 @@ static int unload_module(void)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void print_mappings(void *v_obj, void *where, ao2_prnt_fn *prnt)
|
||||
{
|
||||
struct alias_mailbox_mapping *mapping = v_obj;
|
||||
|
||||
if (!mapping) {
|
||||
return;
|
||||
}
|
||||
prnt(where, "Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Load the module
|
||||
*
|
||||
|
@ -15097,13 +15363,50 @@ static int load_module(void)
|
|||
my_umask = umask(0);
|
||||
umask(my_umask);
|
||||
|
||||
if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
|
||||
inprocess_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 573,
|
||||
inprocess_hash_fn, NULL, inprocess_cmp_fn);
|
||||
if (!inprocess_container) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
alias_mailbox_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
|
||||
alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
|
||||
if (!alias_mailbox_mappings) {
|
||||
ast_log(LOG_ERROR, "Unable to create alias_mailbox_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
res = ao2_container_register("voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Unable to register alias_mailbox_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
mailbox_alias_mappings = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAPPING_BUCKETS,
|
||||
mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
|
||||
if (!mailbox_alias_mappings) {
|
||||
ast_log(LOG_ERROR, "Unable to create mailbox_alias_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
res = ao2_container_register("voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
|
||||
if (res) {
|
||||
ast_log(LOG_ERROR, "Unable to register mailbox_alias_mappings container\n");
|
||||
ao2_cleanup(inprocess_container);
|
||||
ao2_cleanup(alias_mailbox_mappings);
|
||||
ao2_cleanup(mailbox_alias_mappings);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
/* compute the location of the voicemail spool directory */
|
||||
snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
|
||||
|
||||
/* Now that we have a spool directory, clean up old lock files */
|
||||
cleanup_orphaned_lock_files(VM_SPOOL_DIR);
|
||||
|
||||
if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
|
||||
ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
|
||||
}
|
||||
|
|
|
@ -505,6 +505,18 @@
|
|||
<enum name="highest">
|
||||
<para>The highest estimated maximum bitrate is forwarded to the sender.</para>
|
||||
</enum>
|
||||
<enum name="average_all">
|
||||
<para>The average of all estimated maximum bitrates is taken from all
|
||||
receivers in the bridge and a single value is sent to each sender.</para>
|
||||
</enum>
|
||||
<enum name="lowest_all">
|
||||
<para>The lowest estimated maximum bitrate of all receivers in the bridge
|
||||
is taken and sent to each sender.</para>
|
||||
</enum>
|
||||
<enum name="highest_all">
|
||||
<para>The highest estimated maximum bitrate of all receivers in the bridge
|
||||
is taken and sent to each sender.</para>
|
||||
</enum>
|
||||
</enumlist>
|
||||
</description>
|
||||
</configOption>
|
||||
|
@ -1737,7 +1749,8 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
|
|||
|
||||
switch (b_profile.flags
|
||||
& (BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE | BRIDGE_OPT_REMB_BEHAVIOR_LOWEST
|
||||
| BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST)) {
|
||||
| BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST | BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL
|
||||
| BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL | BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL)) {
|
||||
case BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE:
|
||||
ast_cli(a->fd, "REMB Behavior: average\n");
|
||||
break;
|
||||
|
@ -1747,6 +1760,15 @@ static char *handle_cli_confbridge_show_bridge_profile(struct ast_cli_entry *e,
|
|||
case BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST:
|
||||
ast_cli(a->fd, "REMB Behavior: highest\n");
|
||||
break;
|
||||
case BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL:
|
||||
ast_cli(a->fd, "REMB Behavior: average_all\n");
|
||||
break;
|
||||
case BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL:
|
||||
ast_cli(a->fd, "REMB Behavior: lowest_all\n");
|
||||
break;
|
||||
case BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL:
|
||||
ast_cli(a->fd, "REMB Behavior: highest_all\n");
|
||||
break;
|
||||
default:
|
||||
ast_assert(0);
|
||||
break;
|
||||
|
@ -1987,15 +2009,21 @@ void *confbridge_cfg_alloc(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!(cfg->user_profiles = ao2_container_alloc(283, user_hash_cb, user_cmp_cb))) {
|
||||
cfg->user_profiles = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
|
||||
user_hash_cb, NULL, user_cmp_cb);
|
||||
if (!cfg->user_profiles) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(cfg->bridge_profiles = ao2_container_alloc(283, bridge_hash_cb, bridge_cmp_cb))) {
|
||||
cfg->bridge_profiles = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
|
||||
bridge_hash_cb, NULL, bridge_cmp_cb);
|
||||
if (!cfg->bridge_profiles) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(cfg->menus = ao2_container_alloc(283, menu_hash_cb, menu_cmp_cb))) {
|
||||
cfg->menus = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
|
||||
menu_hash_cb, NULL, menu_cmp_cb);
|
||||
if (!cfg->menus) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -2102,7 +2130,10 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab
|
|||
|
||||
ast_clear_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE |
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_LOWEST |
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST);
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST |
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL |
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL |
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL);
|
||||
|
||||
if (!strcasecmp(var->value, "average")) {
|
||||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE);
|
||||
|
@ -2110,6 +2141,12 @@ static int remb_behavior_handler(const struct aco_option *opt, struct ast_variab
|
|||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST);
|
||||
} else if (!strcasecmp(var->value, "highest")) {
|
||||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST);
|
||||
} else if (!strcasecmp(var->value, "average_all")) {
|
||||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL);
|
||||
} else if (!strcasecmp(var->value, "lowest_all")) {
|
||||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL);
|
||||
} else if (!strcasecmp(var->value, "highest_all")) {
|
||||
ast_set_flag(b_profile, BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ static void join_unmarked(struct confbridge_user *user)
|
|||
{
|
||||
conf_add_user_active(user->conference, user);
|
||||
conf_handle_first_join(user->conference);
|
||||
conf_add_post_join_action(user, conf_handle_only_unmarked);
|
||||
conf_add_post_join_action(user, conf_handle_only_person);
|
||||
|
||||
conf_change_state(user, CONF_STATE_SINGLE);
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ static void join_marked(struct confbridge_user *user)
|
|||
{
|
||||
conf_add_user_marked(user->conference, user);
|
||||
conf_handle_first_join(user->conference);
|
||||
conf_add_post_join_action(user, conf_handle_only_person);
|
||||
|
||||
conf_change_state(user, CONF_STATE_SINGLE_MARKED);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ struct confbridge_state *CONF_STATE_INACTIVE = &STATE_INACTIVE;
|
|||
static void join_unmarked(struct confbridge_user *user)
|
||||
{
|
||||
conf_add_user_active(user->conference, user);
|
||||
conf_add_post_join_action(user, conf_handle_only_unmarked);
|
||||
conf_add_post_join_action(user, conf_handle_only_person);
|
||||
|
||||
conf_change_state(user, CONF_STATE_SINGLE);
|
||||
}
|
||||
|
|
|
@ -355,53 +355,6 @@ static struct ast_json *pack_snapshots( struct ast_bridge_snapshot *bridge_snaps
|
|||
return pack_bridge_and_channels(json_bridge, json_channel, msg);
|
||||
}
|
||||
|
||||
enum label_direction {
|
||||
LABEL_DIRECTION_SRC,
|
||||
LABEL_DIRECTION_DEST,
|
||||
};
|
||||
|
||||
static struct ast_stream *get_stream(struct ast_stream_topology *topology,
|
||||
enum ast_media_type m_type)
|
||||
{
|
||||
int count;
|
||||
int i;
|
||||
|
||||
count = ast_stream_topology_get_count(topology);
|
||||
if (count < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
struct ast_stream *s;
|
||||
enum ast_stream_state s_state;
|
||||
enum ast_media_type s_type;
|
||||
|
||||
s = ast_stream_topology_get_stream(topology, i);
|
||||
s_state = ast_stream_get_state(s);
|
||||
s_type = ast_stream_get_type(s);
|
||||
if (s_type == m_type
|
||||
&& (s_state == AST_STREAM_STATE_SENDRECV || s_state == AST_STREAM_STATE_RECVONLY)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_media_labels(struct confbridge_conference *conference,
|
||||
struct ast_channel *src_chan, struct ast_channel *dest_chan, enum label_direction dir)
|
||||
{
|
||||
struct ast_stream_topology *topology;
|
||||
struct ast_stream *stream;
|
||||
struct ast_channel *chan = dir == LABEL_DIRECTION_SRC ? dest_chan : src_chan;
|
||||
|
||||
topology = ast_channel_get_stream_topology(chan);
|
||||
stream = get_stream(topology, AST_MEDIA_TYPE_VIDEO);
|
||||
if (stream) {
|
||||
ast_stream_set_metadata(stream, "SDP:LABEL", ast_channel_uniqueid(chan));
|
||||
}
|
||||
}
|
||||
|
||||
static void send_message(const char *msg_name, char *conf_name, struct ast_json *json_object,
|
||||
struct ast_channel *chan)
|
||||
{
|
||||
|
@ -458,8 +411,8 @@ static void send_message(const char *msg_name, char *conf_name, struct ast_json
|
|||
ast_json_free(json);
|
||||
}
|
||||
|
||||
static void send_event_to_participants(struct confbridge_conference *conference,
|
||||
struct ast_channel *chan, struct stasis_message * msg)
|
||||
void conf_send_event_to_participants(struct confbridge_conference *conference,
|
||||
struct ast_channel *chan, struct stasis_message *msg)
|
||||
{
|
||||
struct ast_bridge_blob *obj = stasis_message_data(msg);
|
||||
struct ast_json *extras = obj->blob;
|
||||
|
@ -505,7 +458,6 @@ static void send_event_to_participants(struct confbridge_conference *conference,
|
|||
continue;
|
||||
}
|
||||
|
||||
set_media_labels(conference, chan, user->chan, LABEL_DIRECTION_SRC);
|
||||
target_json_channel = channel_to_json(target_snapshot, extras, NULL);
|
||||
ao2_ref(target_snapshot, -1);
|
||||
|
||||
|
@ -535,8 +487,6 @@ static void send_event_to_participants(struct confbridge_conference *conference,
|
|||
continue;
|
||||
}
|
||||
|
||||
set_media_labels(conference, chan, user->chan, LABEL_DIRECTION_DEST);
|
||||
|
||||
json_object = pack_snapshots(obj->bridge, obj->channel, extras, NULL, msg);
|
||||
|
||||
if (!json_object) {
|
||||
|
@ -597,13 +547,6 @@ static void confbridge_publish_manager_event(
|
|||
struct confbridge_conference *conference = conf_find_bridge(conference_name);
|
||||
|
||||
channel_text = ast_manager_build_channel_state_string(blob->channel);
|
||||
|
||||
if (conference && ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
|
||||
struct ast_channel *chan = ast_channel_get_by_name(blob->channel->name);
|
||||
|
||||
send_event_to_participants(conference, chan, message);
|
||||
ast_channel_cleanup(chan);
|
||||
}
|
||||
ao2_cleanup(conference);
|
||||
}
|
||||
|
||||
|
@ -678,6 +621,26 @@ static void confbridge_join_cb(void *data, struct stasis_subscription *sub,
|
|||
ast_free(extra_text);
|
||||
}
|
||||
|
||||
static void confbridge_atxfer_cb(void *data, struct stasis_subscription *sub,
|
||||
struct stasis_message *message)
|
||||
{
|
||||
struct ast_attended_transfer_message *msg = stasis_message_data(message);
|
||||
|
||||
if (msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback will get called for ALL attended transfers
|
||||
* so we need to make sure this transfer belongs to
|
||||
* a conference bridge before trying to handle it.
|
||||
*/
|
||||
if (msg->dest_type == AST_ATTENDED_TRANSFER_DEST_APP
|
||||
&& strcmp(msg->dest.app, "ConfBridge") == 0) {
|
||||
confbridge_handle_atxfer(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void confbridge_start_record_cb(void *data, struct stasis_subscription *sub,
|
||||
struct stasis_message *message)
|
||||
{
|
||||
|
@ -796,6 +759,13 @@ int manager_confbridge_init(void)
|
|||
manager_confbridge_shutdown();
|
||||
return -1;
|
||||
}
|
||||
if (stasis_message_router_add(bridge_state_router,
|
||||
ast_attended_transfer_type(),
|
||||
confbridge_atxfer_cb,
|
||||
NULL)) {
|
||||
manager_confbridge_shutdown();
|
||||
return -1;
|
||||
}
|
||||
if (stasis_message_router_add(bridge_state_router,
|
||||
confbridge_leave_type(),
|
||||
confbridge_leave_cb,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "asterisk/channel.h"
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/bridge_features.h"
|
||||
#include "asterisk/stasis_bridges.h"
|
||||
#include "conf_state.h"
|
||||
|
||||
/*! Maximum length of a conference bridge name */
|
||||
|
@ -82,6 +83,9 @@ enum bridge_profile_flags {
|
|||
BRIDGE_OPT_REMB_BEHAVIOR_LOWEST = (1 << 9), /*!< The lowest estimated maximum bitrate is sent to the sender */
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST = (1 << 10), /*!< The highest estimated maximum bitrate is sent to the sender */
|
||||
BRIDGE_OPT_ENABLE_EVENTS = (1 << 11), /*!< Enable sending events to participants */
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_AVERAGE_ALL = (1 << 12), /*!< The average of all REMB reports in the entire bridge is sent to each sender */
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_LOWEST_ALL = (1 << 13), /*!< The lowest estimated maximum bitrate from all receivers is sent to each sender */
|
||||
BRIDGE_OPT_REMB_BEHAVIOR_HIGHEST_ALL = (1 << 14), /*!< The highest estimated maximum bitrate from all receivers is sent to each sender */
|
||||
};
|
||||
|
||||
enum conf_menu_action_id {
|
||||
|
@ -490,13 +494,11 @@ void conf_handle_first_join(struct confbridge_conference *conference);
|
|||
*/
|
||||
int conf_handle_inactive_waitmarked(struct confbridge_user *user);
|
||||
|
||||
/*! \brief Handle actions whenever an unmarked user joins an inactive conference
|
||||
* \note These actions seem like they could apply just as well to a marked user
|
||||
* and possibly be made to happen any time transitioning to a single state.
|
||||
/*! \brief Handle actions whenever an user joins an empty conference
|
||||
*
|
||||
* \param user The unmarked user
|
||||
* \param user The user
|
||||
*/
|
||||
int conf_handle_only_unmarked(struct confbridge_user *user);
|
||||
int conf_handle_only_person(struct confbridge_user *user);
|
||||
|
||||
/*! \brief Handle when a conference moves to having more than one active participant
|
||||
* \param conference The conference bridge with more than one active participant
|
||||
|
@ -701,6 +703,26 @@ int conf_announce_channel_push(struct ast_channel *ast);
|
|||
*/
|
||||
struct confbridge_conference *conf_find_bridge(const char *conference_name);
|
||||
|
||||
/*!
|
||||
* \brief Send events to bridge participants.
|
||||
* \since 15.7
|
||||
* \since 16.1
|
||||
*
|
||||
* \param conference The conference bridge
|
||||
* \param chan The channel triggering the action
|
||||
* \param msg The stasis message describing the event
|
||||
*/
|
||||
void conf_send_event_to_participants(struct confbridge_conference *conference,
|
||||
struct ast_channel *chan, struct stasis_message *msg);
|
||||
|
||||
/*!
|
||||
* \brief Create join/leave events for attended transfers
|
||||
* \since 13.28
|
||||
* \since 16.5
|
||||
*
|
||||
* \param msg The attended transfer stasis message
|
||||
*
|
||||
*/
|
||||
void confbridge_handle_atxfer(struct ast_attended_transfer_message *msg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><title>Release Summary - asterisk-16.6.2</title><h1 align="center"><a name="top">Release Summary</a></h1><h3 align="center">asterisk-16.6.2</h3><h3 align="center">Date: 2019-11-21</h3><h3 align="center"><asteriskteam@digium.com></h3><hr><h2 align="center">Table of Contents</h2><ol>
|
||||
<li><a href="#summary">Summary</a></li>
|
||||
<li><a href="#contributors">Contributors</a></li>
|
||||
<li><a href="#closed_issues">Closed Issues</a></li>
|
||||
<li><a href="#commits">Other Changes</a></li>
|
||||
<li><a href="#diffstat">Diffstat</a></li>
|
||||
</ol><hr><a name="summary"><h2 align="center">Summary</h2></a><center><a href="#top">[Back to Top]</a></center><p>This release has been made to address one or more security vulnerabilities that have been identified. A security advisory document has been published for each vulnerability that includes additional information. Users of versions of Asterisk that are affected are strongly encouraged to review the advisories and determine what action they should take to protect their systems from these issues.</p><p>Security Advisories:</p><ul>
|
||||
<li><a href="http://downloads.asterisk.org/pub/security/AST-2019-006,AST-2019-007.html">AST-2019-006,AST-2019-007</a></li>
|
||||
</ul><p>The data in this summary reflects changes that have been made since the previous release, asterisk-16.6.1.</p><hr><a name="contributors"><h2 align="center">Contributors</h2></a><center><a href="#top">[Back to Top]</a></center><p>This table lists the people who have submitted code, those that have tested patches, as well as those that reported issues on the issue tracker that were resolved in this release. For coders, the number is how many of their patches (of any size) were committed into this release. For testers, the number is the number of times their name was listed as assisting with testing a patch. Finally, for reporters, the number is the number of issues that they reported that were affected by commits that went into this release.</p><table width="100%" border="0">
|
||||
<tr><th width="33%">Coders</th><th width="33%">Testers</th><th width="33%">Reporters</th></tr>
|
||||
<tr valign="top"><td width="33%">1 Asterisk Development Team <asteriskteam@digium.com><br/>1 George Joseph <gjoseph@digium.com><br/>1 Ben Ford <bford@digium.com><br/></td><td width="33%"><td width="33%">1 Eliel Sardañons <eliels@gmail.com><br/>1 Andrey V. T. <avt1203@gmail.com><br/>1 Eliel Sardañons<br/></td></tr>
|
||||
</table><hr><a name="closed_issues"><h2 align="center">Closed Issues</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all issues from the issue tracker that were closed by changes that went into this release.</p><h3>Security</h3><h4>Category: Channels/chan_sip/General</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28589">ASTERISK-28589</a>: chan_sip: Depending on configuration an INVITE can alter Addr of a peer<br/>Reported by: Andrey V. T.<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=ad66cbd0be39198d0016d7133c840289ae6e2dea">[ad66cbd0be]</a> Ben Ford -- chan_sip.c: Prevent address change on unauthenticated SIP request.</li>
|
||||
</ul><br><h4>Category: Core/ManagerInterface</h4><a href="https://issues.asterisk.org/jira/browse/ASTERISK-28580">ASTERISK-28580</a>: Bypass SYSTEM write permission in manager action allows system commands execution<br/>Reported by: Eliel Sardañons<ul>
|
||||
<li><a href="https://code.asterisk.org/code/changelog/asterisk?cs=8cc49544f889b3fc29011751420fda90d8349a1c">[8cc49544f8]</a> George Joseph -- manager.c: Prevent the Originate action from running the Originate app</li>
|
||||
</ul><br><hr><a name="commits"><h2 align="center">Commits Not Associated with an Issue</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a list of all changes that went into this release that did not reference a JIRA issue.</p><table width="100%" border="1">
|
||||
<tr><th>Revision</th><th>Author</th><th>Summary</th></tr>
|
||||
<tr><td><a href="https://code.asterisk.org/code/changelog/asterisk?cs=a4248c671a5c9a36f9d7277af8593b73352f038a">a4248c671a</a></td><td>Asterisk Development Team</td><td>Update CHANGES and UPGRADE.txt for 16.6.2</td></tr>
|
||||
</table><hr><a name="diffstat"><h2 align="center">Diffstat Results</h2></a><center><a href="#top">[Back to Top]</a></center><p>This is a summary of the changes to the source code that went into this release that was generated using the diffstat utility.</p><pre>0 files changed</pre><br></html>
|
|
@ -0,0 +1,111 @@
|
|||
Release Summary
|
||||
|
||||
asterisk-16.6.2
|
||||
|
||||
Date: 2019-11-21
|
||||
|
||||
<asteriskteam@digium.com>
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Summary
|
||||
2. Contributors
|
||||
3. Closed Issues
|
||||
4. Other Changes
|
||||
5. Diffstat
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Summary
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This release has been made to address one or more security vulnerabilities
|
||||
that have been identified. A security advisory document has been published
|
||||
for each vulnerability that includes additional information. Users of
|
||||
versions of Asterisk that are affected are strongly encouraged to review
|
||||
the advisories and determine what action they should take to protect their
|
||||
systems from these issues.
|
||||
|
||||
Security Advisories:
|
||||
|
||||
* AST-2019-006,AST-2019-007
|
||||
|
||||
The data in this summary reflects changes that have been made since the
|
||||
previous release, asterisk-16.6.1.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Contributors
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This table lists the people who have submitted code, those that have
|
||||
tested patches, as well as those that reported issues on the issue tracker
|
||||
that were resolved in this release. For coders, the number is how many of
|
||||
their patches (of any size) were committed into this release. For testers,
|
||||
the number is the number of times their name was listed as assisting with
|
||||
testing a patch. Finally, for reporters, the number is the number of
|
||||
issues that they reported that were affected by commits that went into
|
||||
this release.
|
||||
|
||||
Coders Testers Reporters
|
||||
1 Asterisk Development Team 1 Eliel Sardañons
|
||||
1 George Joseph 1 Andrey V. T.
|
||||
1 Ben Ford 1 Eliel Sardañons
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Closed Issues
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all issues from the issue tracker that were closed by
|
||||
changes that went into this release.
|
||||
|
||||
Security
|
||||
|
||||
Category: Channels/chan_sip/General
|
||||
|
||||
ASTERISK-28589: chan_sip: Depending on configuration an INVITE can alter
|
||||
Addr of a peer
|
||||
Reported by: Andrey V. T.
|
||||
* [ad66cbd0be] Ben Ford -- chan_sip.c: Prevent address change on
|
||||
unauthenticated SIP request.
|
||||
|
||||
Category: Core/ManagerInterface
|
||||
|
||||
ASTERISK-28580: Bypass SYSTEM write permission in manager action allows
|
||||
system commands execution
|
||||
Reported by: Eliel Sardañons
|
||||
* [8cc49544f8] George Joseph -- manager.c: Prevent the Originate action
|
||||
from running the Originate app
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Commits Not Associated with an Issue
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a list of all changes that went into this release that did not
|
||||
reference a JIRA issue.
|
||||
|
||||
+------------------------------------------------------------------------+
|
||||
| Revision | Author | Summary |
|
||||
|------------+---------------------------+-------------------------------|
|
||||
| a4248c671a | Asterisk Development Team | Update CHANGES and |
|
||||
| | | UPGRADE.txt for 16.6.2 |
|
||||
+------------------------------------------------------------------------+
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Diffstat Results
|
||||
|
||||
[Back to Top]
|
||||
|
||||
This is a summary of the changes to the source code that went into this
|
||||
release that was generated using the diffstat utility.
|
||||
|
||||
0 files changed
|
|
@ -203,3 +203,105 @@ if test "x${PBX_$1}" = "x1"; then
|
|||
LIBS="${ast_ext_lib_check_shared_saved_libs}"
|
||||
fi
|
||||
])
|
||||
|
||||
# Check for existence of a given package ($1), either looking up a function
|
||||
# in a library, or, if no function is supplied, only check for the
|
||||
# existence of the header files. Then compile, link and run the supplied
|
||||
# code fragment to make the final determination.
|
||||
|
||||
# AST_EXT_LIB_EXTRA_CHECK([package], [library], [function], [header],
|
||||
# [extra libs], [extra cflags], [AC_LANG_PROGRAM(extra check code...)],
|
||||
# ["checking for" display string], ["HAVE_package_" extra variable to set])
|
||||
AC_DEFUN([AST_EXT_LIB_EXTRA_CHECK],
|
||||
[
|
||||
if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
|
||||
pbxlibdir=""
|
||||
# if --with-$1=DIR has been specified, use it.
|
||||
if test "x${$1_DIR}" != "x"; then
|
||||
if test -d ${$1_DIR}/lib; then
|
||||
pbxlibdir="-L${$1_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${$1_DIR}"
|
||||
fi
|
||||
fi
|
||||
m4_ifval([$3], [
|
||||
ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
|
||||
CFLAGS="${CFLAGS} $6"
|
||||
AC_CHECK_LIB([$2], [$3], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], [${pbxlibdir} $5])
|
||||
CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
|
||||
], [
|
||||
# empty lib, assume only headers
|
||||
AST_$1_FOUND=yes
|
||||
])
|
||||
|
||||
# now check for the header.
|
||||
if test "${AST_$1_FOUND}" = "yes"; then
|
||||
$1_LIB="${pbxlibdir} -l$2 $5"
|
||||
# if --with-$1=DIR has been specified, use it.
|
||||
if test "x${$1_DIR}" != "x"; then
|
||||
$1_INCLUDE="-I${$1_DIR}/include"
|
||||
fi
|
||||
$1_INCLUDE="${$1_INCLUDE} $6"
|
||||
m4_ifval([$4], [
|
||||
# check for the header
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
|
||||
AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
], [
|
||||
# no header, assume found
|
||||
$1_HEADER_FOUND="1"
|
||||
])
|
||||
fi
|
||||
# Validate the package with the supplied code.
|
||||
if test "x${$1_HEADER_FOUND}" = "x1" ; then
|
||||
AC_MSG_CHECKING(for $8)
|
||||
ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
|
||||
ast_ext_lib_check_saved_LIBS="${LIBS}"
|
||||
LIBS="${$1_LIB}"
|
||||
AC_LINK_IFELSE(
|
||||
[$7],
|
||||
[
|
||||
if test "x${cross_compiling}" = "xyes" ; then
|
||||
$1_VALIDATED="1"
|
||||
AC_MSG_RESULT([yes (guessed for cross-compile)])
|
||||
else
|
||||
./conftest$EXEEXT
|
||||
if test $? -eq 0 ; then
|
||||
$1_VALIDATED="1"
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(no)
|
||||
]
|
||||
)
|
||||
CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
|
||||
LIBS="${ast_ext_lib_check_saved_LIBS}"
|
||||
fi
|
||||
|
||||
if test "x${$1_VALIDATED}" = "x1" ; then
|
||||
m4_ifval([$3], [], [
|
||||
# only checking headers -> no library
|
||||
$1_LIB=""
|
||||
])
|
||||
PBX_$1=1
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
[@%:@define] HAVE_$1 1
|
||||
_ACEOF
|
||||
m4_ifval([$9], [
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
[@%:@define] HAVE_$1_$9 1
|
||||
_ACEOF
|
||||
])
|
||||
else
|
||||
$1_LIB=""
|
||||
$1_INCLUDE=""
|
||||
fi
|
||||
fi
|
||||
m4_ifval([$9], [AH_TEMPLATE(m4_bpatsubst([[HAVE_$1_$9]], [(.*)]), [Define if $8])])
|
||||
])
|
||||
|
|
|
@ -213,6 +213,7 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct
|
|||
ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(bridge_channel->chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
|
||||
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
|
||||
}
|
||||
|
||||
|
@ -400,6 +401,7 @@ static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, stru
|
|||
ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
|
||||
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
|
||||
}
|
||||
|
||||
|
|
|
@ -703,6 +703,18 @@ static int native_rtp_bridge_compatible_check(struct ast_bridge *bridge, struct
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (glue0->audio.instance && glue1->audio.instance) {
|
||||
unsigned int framing_inst0, framing_inst1;
|
||||
framing_inst0 = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(glue0->audio.instance));
|
||||
framing_inst1 = ast_rtp_codecs_get_framing(ast_rtp_instance_get_codecs(glue1->audio.instance));
|
||||
if (framing_inst0 != framing_inst1) {
|
||||
/* ptimes are asymmetric on the two call legs so we can't use the native bridge */
|
||||
ast_debug(1, "Asymmetric ptimes on the two call legs (%u != %u). Cannot native bridge in RTP\n",
|
||||
framing_inst0, framing_inst1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
read_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawreadformat(bc0->chan));
|
||||
read_ptime1 = ast_format_cap_get_format_framing(cap1, ast_channel_rawreadformat(bc1->chan));
|
||||
write_ptime0 = ast_format_cap_get_format_framing(cap0, ast_channel_rawwriteformat(bc0->chan));
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "asterisk/stream.h"
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/vector.h"
|
||||
|
@ -75,8 +77,8 @@ struct softmix_remb_collector {
|
|||
struct ast_frame frame;
|
||||
/*! The REMB to send to the source which is collecting REMB reports */
|
||||
struct ast_rtp_rtcp_feedback feedback;
|
||||
/*! The maximum bitrate */
|
||||
unsigned int bitrate;
|
||||
/*! The maximum bitrate (A single precision floating point is big enough) */
|
||||
float bitrate;
|
||||
};
|
||||
|
||||
struct softmix_stats {
|
||||
|
@ -498,10 +500,11 @@ static int is_video_dest(const struct ast_stream *stream, const char *source_cha
|
|||
}
|
||||
|
||||
static int append_source_streams(struct ast_stream_topology *dest,
|
||||
const char *channel_name,
|
||||
const char *channel_name, const char *sdp_label,
|
||||
const struct ast_stream_topology *source)
|
||||
{
|
||||
int i;
|
||||
const char *stream_identify;
|
||||
|
||||
for (i = 0; i < ast_stream_topology_get_count(source); ++i) {
|
||||
struct ast_stream *stream;
|
||||
|
@ -513,8 +516,13 @@ static int append_source_streams(struct ast_stream_topology *dest,
|
|||
continue;
|
||||
}
|
||||
|
||||
stream_identify = ast_stream_get_metadata(stream, "MSID:LABEL");
|
||||
if (!stream_identify) {
|
||||
stream_identify = ast_stream_get_name(stream);
|
||||
}
|
||||
|
||||
if (ast_asprintf(&stream_clone_name, "%s_%s_%s", SOFTBRIDGE_VIDEO_DEST_PREFIX,
|
||||
channel_name, ast_stream_get_name(stream)) < 0) {
|
||||
channel_name, stream_identify) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -523,6 +531,12 @@ static int append_source_streams(struct ast_stream_topology *dest,
|
|||
if (!stream_clone) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Sends an "a:label" attribute in the SDP for participant event correlation */
|
||||
if (!ast_strlen_zero(sdp_label)) {
|
||||
ast_stream_set_metadata(stream_clone, "SDP:LABEL", sdp_label);
|
||||
}
|
||||
|
||||
if (ast_stream_topology_append_stream(dest, stream_clone) < 0) {
|
||||
ast_stream_free(stream_clone);
|
||||
return -1;
|
||||
|
@ -585,9 +599,11 @@ static int append_all_streams(struct ast_stream_topology *dest,
|
|||
* \param joiner The channel that is joining the softmix bridge
|
||||
* \param participants The current participants in the softmix bridge
|
||||
*/
|
||||
static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast_bridge_channels_list *participants)
|
||||
static void sfu_topologies_on_join(struct ast_bridge *bridge,
|
||||
struct ast_bridge_channel *joiner)
|
||||
{
|
||||
struct ast_stream_topology *joiner_video = NULL;
|
||||
struct ast_bridge_channels_list *participants = &bridge->channels;
|
||||
struct ast_bridge_channel *participant;
|
||||
int res;
|
||||
struct softmix_channel *sc;
|
||||
|
@ -600,7 +616,9 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast
|
|||
sc = joiner->tech_pvt;
|
||||
|
||||
ast_channel_lock(joiner->chan);
|
||||
res = append_source_streams(joiner_video, ast_channel_name(joiner->chan), ast_channel_get_stream_topology(joiner->chan));
|
||||
res = append_source_streams(joiner_video, ast_channel_name(joiner->chan),
|
||||
bridge->softmix.send_sdp_label ? ast_channel_uniqueid(joiner->chan) : NULL,
|
||||
ast_channel_get_stream_topology(joiner->chan));
|
||||
sc->topology = ast_stream_topology_clone(ast_channel_get_stream_topology(joiner->chan));
|
||||
ast_channel_unlock(joiner->chan);
|
||||
|
||||
|
@ -614,7 +632,8 @@ static void sfu_topologies_on_join(struct ast_bridge_channel *joiner, struct ast
|
|||
}
|
||||
ast_channel_lock(participant->chan);
|
||||
res = append_source_streams(sc->topology, ast_channel_name(participant->chan),
|
||||
ast_channel_get_stream_topology(participant->chan));
|
||||
bridge->softmix.send_sdp_label ? ast_channel_uniqueid(participant->chan) : NULL,
|
||||
ast_channel_get_stream_topology(participant->chan));
|
||||
ast_channel_unlock(participant->chan);
|
||||
if (res) {
|
||||
goto cleanup;
|
||||
|
@ -704,7 +723,7 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||
bridge_channel, 0, set_binaural, pos_id, is_announcement);
|
||||
|
||||
if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) {
|
||||
sfu_topologies_on_join(bridge_channel, &bridge->channels);
|
||||
sfu_topologies_on_join(bridge, bridge_channel);
|
||||
}
|
||||
|
||||
softmix_poke_thread(softmix_data);
|
||||
|
@ -1063,9 +1082,11 @@ static int remove_all_original_streams(struct ast_stream_topology *dest,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sfu_topologies_on_source_change(struct ast_bridge_channel *source, struct ast_bridge_channels_list *participants)
|
||||
static void sfu_topologies_on_source_change(struct ast_bridge *bridge,
|
||||
struct ast_bridge_channel *source)
|
||||
{
|
||||
struct ast_stream_topology *source_video = NULL;
|
||||
struct ast_bridge_channels_list *participants = &bridge->channels;
|
||||
struct ast_bridge_channel *participant;
|
||||
int res;
|
||||
|
||||
|
@ -1075,7 +1096,9 @@ static void sfu_topologies_on_source_change(struct ast_bridge_channel *source, s
|
|||
}
|
||||
|
||||
ast_channel_lock(source->chan);
|
||||
res = append_source_streams(source_video, ast_channel_name(source->chan), ast_channel_get_stream_topology(source->chan));
|
||||
res = append_source_streams(source_video, ast_channel_name(source->chan),
|
||||
bridge->softmix.send_sdp_label ? ast_channel_uniqueid(source->chan) : NULL,
|
||||
ast_channel_get_stream_topology(source->chan));
|
||||
ast_channel_unlock(source->chan);
|
||||
if (res) {
|
||||
goto cleanup;
|
||||
|
@ -1198,7 +1221,7 @@ static int softmix_bridge_write_control(struct ast_bridge *bridge, struct ast_br
|
|||
break;
|
||||
case AST_CONTROL_STREAM_TOPOLOGY_SOURCE_CHANGED:
|
||||
if (bridge->softmix.video_mode.mode == AST_BRIDGE_VIDEO_MODE_SFU) {
|
||||
sfu_topologies_on_source_change(bridge_channel, &bridge->channels);
|
||||
sfu_topologies_on_source_change(bridge, bridge_channel);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1309,11 +1332,41 @@ static int softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_cha
|
|||
return res;
|
||||
}
|
||||
|
||||
static void remb_collect_report_all(struct ast_bridge *bridge, struct softmix_bridge_data *softmix_data,
|
||||
float bitrate)
|
||||
{
|
||||
if (!softmix_data->bitrate) {
|
||||
softmix_data->bitrate = bitrate;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior) {
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL:
|
||||
softmix_data->bitrate = (softmix_data->bitrate + bitrate) / 2;
|
||||
break;
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL:
|
||||
if (bitrate < softmix_data->bitrate) {
|
||||
softmix_data->bitrate = bitrate;
|
||||
}
|
||||
break;
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL:
|
||||
if (bitrate > softmix_data->bitrate) {
|
||||
softmix_data->bitrate = bitrate;
|
||||
}
|
||||
break;
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE:
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST:
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST:
|
||||
/* These will never actually get hit due to being handled by remb_collect_report below */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel,
|
||||
struct softmix_bridge_data *softmix_data, struct softmix_channel *sc)
|
||||
{
|
||||
int i;
|
||||
unsigned int bitrate;
|
||||
float bitrate;
|
||||
|
||||
/* If there are no video sources that we are a receiver of then we have noone to
|
||||
* report REMB to.
|
||||
|
@ -1332,6 +1385,14 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
|
|||
return;
|
||||
}
|
||||
|
||||
/* If we are using the "all" variants then we should use the bridge bitrate to store information */
|
||||
if (bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL ||
|
||||
bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL ||
|
||||
bridge->softmix.video_mode.mode_data.sfu_data.remb_behavior == AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL) {
|
||||
remb_collect_report_all(bridge, softmix_data, bitrate);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < AST_VECTOR_SIZE(&sc->video_sources); ++i) {
|
||||
struct softmix_remb_collector *collector;
|
||||
|
||||
|
@ -1357,6 +1418,11 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
|
|||
collector->bitrate = bitrate;
|
||||
}
|
||||
break;
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_AVERAGE_ALL:
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_LOWEST_ALL:
|
||||
case AST_BRIDGE_VIDEO_SFU_REMB_HIGHEST_ALL:
|
||||
/* These will never actually get hit due to being handled by remb_collect_report_all above */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,27 +1433,71 @@ static void remb_collect_report(struct ast_bridge *bridge, struct ast_bridge_cha
|
|||
sc->remb.br_exp = 0;
|
||||
}
|
||||
|
||||
static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct softmix_channel *sc)
|
||||
static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct softmix_bridge_data *softmix_data,
|
||||
struct softmix_channel *sc)
|
||||
{
|
||||
float bitrate = softmix_data->bitrate;
|
||||
int i;
|
||||
int exp;
|
||||
|
||||
if (!sc->remb_collector) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no bridge level bitrate fall back to collector level */
|
||||
if (!bitrate) {
|
||||
bitrate = sc->remb_collector->bitrate;
|
||||
sc->remb_collector->bitrate = 0;
|
||||
}
|
||||
|
||||
/* We always do this calculation as even when the bitrate is zero the browser
|
||||
* still prefers it to be accurate instead of lying.
|
||||
*
|
||||
* The mantissa only has 18 bits available, so make sure it fits. Adjust the
|
||||
* value and exponent for those values that don't.
|
||||
*
|
||||
* For example given the following:
|
||||
*
|
||||
* bitrate = 123456789.0
|
||||
* frexp(bitrate, &exp);
|
||||
*
|
||||
* 'exp' should now equal 27 (number of bits needed to represent the value). Since
|
||||
* the mantissa must fit into an 18-bit unsigned integer, and the given bitrate is
|
||||
* too large to fit, we must subtract 18 from the exponent in order to get the
|
||||
* number of times the bitrate will fit into that size integer.
|
||||
*
|
||||
* exp -= 18;
|
||||
*
|
||||
* 'exp' is now equal to 9. Now we can get the mantissa that fits into an 18-bit
|
||||
* unsigned integer by dividing the bitrate by 2^exp:
|
||||
*
|
||||
* mantissa = 123456789.0 / 2^9
|
||||
*
|
||||
* This makes the final mantissa equal to 241126 (implicitly cast), which is less
|
||||
* than 262143 (the max value that can be put into an unsigned 18-bit integer).
|
||||
* So now we have the following:
|
||||
*
|
||||
* exp = 9;
|
||||
* mantissa = 241126;
|
||||
*
|
||||
* If we multiply that back we should come up with something close to the original
|
||||
* bit rate:
|
||||
*
|
||||
* 241126 * 2^9 = 123456512
|
||||
*
|
||||
* Precision is lost due to the nature of floating point values. Easier to why from
|
||||
* the binary:
|
||||
*
|
||||
* 241126 * 2^9 = 241126 << 9 = 111010110111100110 << 9 = 111010110111100110000000000
|
||||
*
|
||||
* Precision on the "lower" end is lost due to zeros being shifted in. This loss is
|
||||
* both expected and acceptable.
|
||||
*/
|
||||
sc->remb_collector->feedback.remb.br_mantissa = sc->remb_collector->bitrate;
|
||||
sc->remb_collector->feedback.remb.br_exp = 0;
|
||||
frexp(bitrate, &exp);
|
||||
exp = exp > 18 ? exp - 18 : 0;
|
||||
|
||||
/* The mantissa only has 18 bits available, so while it exceeds them we bump
|
||||
* up the exp.
|
||||
*/
|
||||
while (sc->remb_collector->feedback.remb.br_mantissa > 0x3ffff) {
|
||||
sc->remb_collector->feedback.remb.br_mantissa = sc->remb_collector->feedback.remb.br_mantissa >> 1;
|
||||
sc->remb_collector->feedback.remb.br_exp++;
|
||||
}
|
||||
sc->remb_collector->feedback.remb.br_mantissa = bitrate / (1 << exp);
|
||||
sc->remb_collector->feedback.remb.br_exp = exp;
|
||||
|
||||
for (i = 0; i < AST_VECTOR_SIZE(&bridge_channel->stream_map.to_bridge); ++i) {
|
||||
int bridge_num = AST_VECTOR_GET(&bridge_channel->stream_map.to_bridge, i);
|
||||
|
@ -1407,8 +1517,6 @@ static void remb_send_report(struct ast_bridge_channel *bridge_channel, struct s
|
|||
sc->remb_collector->frame.stream_num = bridge_num;
|
||||
ast_bridge_channel_queue_frame(bridge_channel, &sc->remb_collector->frame);
|
||||
}
|
||||
|
||||
sc->remb_collector->bitrate = 0;
|
||||
}
|
||||
|
||||
static void gather_softmix_stats(struct softmix_stats *stats,
|
||||
|
@ -1768,10 +1876,15 @@ static int softmix_mixing_loop(struct ast_bridge *bridge)
|
|||
ast_bridge_channel_queue_frame(bridge_channel, &sc->write_frame);
|
||||
|
||||
if (remb_update) {
|
||||
remb_send_report(bridge_channel, sc);
|
||||
remb_send_report(bridge_channel, softmix_data, sc);
|
||||
}
|
||||
}
|
||||
|
||||
if (remb_update) {
|
||||
/* In case we are doing bridge level REMB reset the bitrate so we start fresh */
|
||||
softmix_data->bitrate = 0;
|
||||
}
|
||||
|
||||
update_all_rates = 0;
|
||||
if (!stat_iteration_counter) {
|
||||
update_all_rates = analyse_softmix_stats(&stats, softmix_data,
|
||||
|
@ -2171,6 +2284,7 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st
|
|||
|
||||
for (i = 0; i < ast_stream_topology_get_count(topology); ++i) {
|
||||
struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
|
||||
const char *stream_identify;
|
||||
|
||||
if (is_video_source(stream)) {
|
||||
AST_VECTOR_APPEND(&media_types, AST_MEDIA_TYPE_VIDEO);
|
||||
|
@ -2187,7 +2301,12 @@ static void softmix_bridge_stream_topology_changed(struct ast_bridge *bridge, st
|
|||
*/
|
||||
ast_channel_unlock(participant->chan);
|
||||
ast_bridge_channel_unlock(participant);
|
||||
map_source_to_destinations(ast_stream_get_name(stream), ast_channel_name(participant->chan),
|
||||
|
||||
stream_identify = ast_stream_get_metadata(stream, "MSID:LABEL");
|
||||
if (!stream_identify) {
|
||||
stream_identify = ast_stream_get_name(stream);
|
||||
}
|
||||
map_source_to_destinations(stream_identify, ast_channel_name(participant->chan),
|
||||
AST_VECTOR_SIZE(&media_types) - 1, &bridge->channels);
|
||||
ast_bridge_channel_lock(participant);
|
||||
ast_channel_lock(participant->chan);
|
||||
|
@ -2383,7 +2502,7 @@ AST_TEST_DEFINE(sfu_append_source_streams)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (append_source_streams(topology_alice, "PJSIP/Bob-00000001", topology_bob)) {
|
||||
if (append_source_streams(topology_alice, "PJSIP/Bob-00000001", NULL, topology_bob)) {
|
||||
ast_test_status_update(test, "Failed to append Bob's streams to Alice\n");
|
||||
goto end;
|
||||
}
|
||||
|
@ -2402,7 +2521,7 @@ AST_TEST_DEFINE(sfu_append_source_streams)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (append_source_streams(topology_bob, "PJSIP/Alice-00000000", topology_alice)) {
|
||||
if (append_source_streams(topology_bob, "PJSIP/Alice-00000000", NULL, topology_alice)) {
|
||||
ast_test_status_update(test, "Failed to append Alice's streams to Bob\n");
|
||||
goto end;
|
||||
}
|
||||
|
|
|
@ -216,6 +216,8 @@ struct softmix_bridge_data {
|
|||
struct timeval last_remb_update;
|
||||
/*! Per-bridge stream REMB collectors, which flow back to video source */
|
||||
AST_VECTOR(, struct softmix_remb_collector *) remb_collectors;
|
||||
/*! Per-bridge REMB bitrate */
|
||||
float bitrate;
|
||||
};
|
||||
|
||||
struct softmix_mixing_array {
|
||||
|
|
|
@ -14,26 +14,36 @@ END
|
|||
if ${GREP} "AST_DEVMODE" makeopts | ${GREP} -q "yes"
|
||||
then
|
||||
echo "#define AST_DEVMODE 1"
|
||||
BUILDOPTS="AST_DEVMODE"
|
||||
# AST_DEVMODE is no longer an API/ABI affecting option so it no longer
|
||||
# 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
|
||||
echo "#define ${x} 1"
|
||||
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}" = "LOW_MEMORY" \
|
||||
-o "${x}" = "MALLOC_DEBUG" \
|
||||
-o "${x}" = "RADIO_RELAX" \
|
||||
-o "${x}" = "REBUILD_PARSERS" \
|
||||
-o "${x}" = "REF_DEBUG" ; then
|
||||
# These aren't ABI affecting options, keep them out of AST_BUILDOPTS
|
||||
-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
|
||||
|
||||
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
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
AWK=${AWK:-awk}
|
||||
GIT=${GIT:-git}
|
||||
GREP=${GREP:-grep}
|
||||
MAINLINE_BRANCH=master
|
||||
|
||||
if [ -f ${1}/.version ]; then
|
||||
cat ${1}/.version
|
||||
|
@ -101,6 +100,7 @@ elif [ -d ${1}/.git ]; then
|
|||
MODIFIED=""
|
||||
SVN_REV=`${GIT} log --pretty=full -1 | ${GREP} -F "git-svn-id:" | sed -e "s/.*\@\([^\s]*\)\s.*/\1/g"`
|
||||
if [ -z "$SVN_REV" ]; then
|
||||
MAINLINE_BRANCH=$(git config -f .gitreview --get gerrit.defaultbranch)
|
||||
VERSION=`${GIT} describe --long --always --tags --dirty=M 2> /dev/null`
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ "`${GIT} ls-files -m | wc -l`" != "0" ]; then
|
||||
|
|
|
@ -82,3 +82,4 @@ HAVE_ADDRESS_SANITIZER=@AST_ADDRESS_SANITIZER@
|
|||
HAVE_LEAK_SANITIZER=@AST_LEAK_SANITIZER@
|
||||
HAVE_THREAD_SANITIZER=@AST_THREAD_SANITIZER@
|
||||
HAVE_UNDEFINED_SANITIZER=@AST_UNDEFINED_SANITIZER@
|
||||
NO_BINARY_MODULES=@PBX_NO_BINARY_MODULES@
|
||||
|
|
|
@ -338,7 +338,7 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
res = SQLPrepare(stmt, (unsigned char *) data, SQL_NTS);
|
||||
res = ast_odbc_prepare(obj, stmt, data);
|
||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *) data);
|
||||
SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
|
||||
|
|
|
@ -153,7 +153,7 @@ static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data)
|
|||
SQLBindParameter(stmt, i + 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->sequence, 0, NULL);
|
||||
}
|
||||
|
||||
ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS);
|
||||
ODBC_res = ast_odbc_execute_sql(obj, stmt, sqlcmd);
|
||||
|
||||
if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "cdr_odbc: Error in ExecDirect: %d, query is: %s\n", ODBC_res, sqlcmd);
|
||||
|
|
|
@ -184,15 +184,27 @@ static void pgsql_reconnect(void)
|
|||
conn = NULL;
|
||||
}
|
||||
|
||||
ast_str_set(&conn_info, 0, "host=%s port=%s dbname=%s user=%s",
|
||||
pghostname, pgdbport, pgdbname, pgdbuser);
|
||||
|
||||
if (!ast_strlen_zero(pgappname)) {
|
||||
ast_str_append(&conn_info, 0, " application_name=%s", pgappname);
|
||||
if (!ast_strlen_zero(pghostname)) {
|
||||
ast_str_append(&conn_info, 0, "host=%s ", pghostname);
|
||||
}
|
||||
if (!ast_strlen_zero(pgdbport)) {
|
||||
ast_str_append(&conn_info, 0, "port=%s ", pgdbport);
|
||||
}
|
||||
if (!ast_strlen_zero(pgdbname)) {
|
||||
ast_str_append(&conn_info, 0, "dbname=%s ", pgdbname);
|
||||
}
|
||||
if (!ast_strlen_zero(pgdbuser)) {
|
||||
ast_str_append(&conn_info, 0, "user=%s ", pgdbuser);
|
||||
}
|
||||
if (!ast_strlen_zero(pgappname)) {
|
||||
ast_str_append(&conn_info, 0, "application_name=%s ", pgappname);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(pgpassword)) {
|
||||
ast_str_append(&conn_info, 0, " password=%s", pgpassword);
|
||||
ast_str_append(&conn_info, 0, "password=%s", pgpassword);
|
||||
}
|
||||
if (ast_str_strlen(conn_info) == 0) {
|
||||
ast_log(LOG_ERROR, "Connection string is blank.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
conn = PQconnectdb(ast_str_buffer(conn_info));
|
||||
|
|
|
@ -323,7 +323,7 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
|
||||
res = ast_odbc_prepare(obj, stmt, sql);
|
||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
|
||||
SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
|
||||
|
|
|
@ -29,6 +29,7 @@ $(call MOD_ADD_C,chan_pjsip,$(wildcard pjsip/*.c))
|
|||
$(call MOD_ADD_C,chan_dahdi,$(wildcard dahdi/*.c) sig_analog.c sig_pri.c sig_ss7.c)
|
||||
$(call MOD_ADD_C,chan_misdn,misdn_config.c misdn/isdn_lib.c misdn/isdn_msg_parser.c)
|
||||
|
||||
chan_dahdi.o: _ASTCFLAGS+=$(call get_menuselect_cflags,LOTS_OF_SPANS)
|
||||
chan_mgcp.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
chan_unistim.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
chan_phone.o: _ASTCFLAGS+=$(AST_NO_FORMAT_TRUNCATION)
|
||||
|
|
|
@ -849,10 +849,10 @@ static char *cli_console_dial(struct ast_cli_entry *e, int cmd, struct ast_cli_a
|
|||
if (a->argc == e->args + 1) {
|
||||
char *ext = NULL, *con = NULL;
|
||||
s = ast_ext_ctx(pvt, a->argv[e->args], &ext, &con);
|
||||
ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
|
||||
a->argv[e->args], mye, myc);
|
||||
mye = ext;
|
||||
myc = con;
|
||||
ast_debug(1, "provided '%s', exten '%s' context '%s'\n",
|
||||
a->argv[e->args], mye, myc);
|
||||
}
|
||||
|
||||
/* supply default values if needed */
|
||||
|
@ -1534,7 +1534,9 @@ static int load_module(void)
|
|||
|
||||
init_pvt(&globals, NULL);
|
||||
|
||||
if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
|
||||
pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NUM_PVT_BUCKETS,
|
||||
pvt_hash_cb, NULL, pvt_cmp_cb);
|
||||
if (!pvts)
|
||||
goto return_error;
|
||||
|
||||
if (load_config(0))
|
||||
|
|
|
@ -107,7 +107,7 @@
|
|||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/tdd.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/manager.h"
|
||||
|
@ -185,6 +185,9 @@
|
|||
<enum name="dahdi_span">
|
||||
<para>R/O DAHDI span related to this channel.</para>
|
||||
</enum>
|
||||
<enum name="dahdi_group">
|
||||
<para>R/O DAHDI logical group related to this channel.</para>
|
||||
</enum>
|
||||
<enum name="dahdi_type">
|
||||
<para>R/O DAHDI channel type, one of:</para>
|
||||
<enumlist>
|
||||
|
@ -462,6 +465,9 @@
|
|||
<synopsis>Raised when a DAHDI channel is created or an underlying technology is associated with a DAHDI channel.</synopsis>
|
||||
<syntax>
|
||||
<channel_snapshot/>
|
||||
<parameter name="DAHDIGroup">
|
||||
<para>The DAHDI logical group associated with this channel.</para>
|
||||
</parameter>
|
||||
<parameter name="DAHDISpan">
|
||||
<para>The DAHDI span associated with this channel.</para>
|
||||
</parameter>
|
||||
|
@ -738,15 +744,24 @@ struct dahdi_mfcr2_conf {
|
|||
|
||||
/* MFC-R2 pseudo-link structure */
|
||||
struct dahdi_mfcr2 {
|
||||
int index; /*!< Unique index for CLI */
|
||||
pthread_t r2master; /*!< Thread of master */
|
||||
openr2_context_t *protocol_context; /*!< OpenR2 context handle */
|
||||
struct dahdi_pvt *pvts[SIG_MFCR2_MAX_CHANNELS]; /*!< Member channel pvt structs */
|
||||
int numchans; /*!< Number of channels in this R2 block */
|
||||
struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
|
||||
int live_chans; /*!< Number of unremoved channels in this R2 block */
|
||||
int nodev; /*!< Link disconnected? */
|
||||
struct dahdi_mfcr2_conf conf; /*!< Configuration used to setup this pseudo-link */
|
||||
};
|
||||
|
||||
/* malloc'd array of malloc'd r2links */
|
||||
static struct dahdi_mfcr2 **r2links;
|
||||
struct r2link_entry {
|
||||
struct dahdi_mfcr2 mfcr2;
|
||||
AST_LIST_ENTRY(r2link_entry) list;
|
||||
};
|
||||
static AST_LIST_HEAD_STATIC(r2links, r2link_entry);
|
||||
static struct r2links nodev_r2links = AST_LIST_HEAD_INIT_VALUE;
|
||||
|
||||
|
||||
/* how many r2links have been malloc'd */
|
||||
static int r2links_count = 0;
|
||||
|
||||
|
@ -1727,21 +1742,24 @@ static struct ast_manager_event_blob *dahdichannel_to_ami(struct stasis_message
|
|||
{
|
||||
RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
|
||||
struct ast_channel_blob *obj = stasis_message_data(msg);
|
||||
struct ast_json *span, *channel;
|
||||
struct ast_json *group, *span, *channel;
|
||||
|
||||
channel_string = ast_manager_build_channel_state_string(obj->snapshot);
|
||||
if (!channel_string) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
group = ast_json_object_get(obj->blob, "group");
|
||||
span = ast_json_object_get(obj->blob, "span");
|
||||
channel = ast_json_object_get(obj->blob, "channel");
|
||||
|
||||
return ast_manager_event_blob_create(EVENT_FLAG_CALL, "DAHDIChannel",
|
||||
"%s"
|
||||
"DAHDIGroup: %llu\r\n"
|
||||
"DAHDISpan: %u\r\n"
|
||||
"DAHDIChannel: %s\r\n",
|
||||
ast_str_buffer(channel_string),
|
||||
(ast_group_t)ast_json_integer_get(group),
|
||||
(unsigned int)ast_json_integer_get(span),
|
||||
ast_json_string_get(channel));
|
||||
}
|
||||
|
@ -1751,13 +1769,14 @@ STASIS_MESSAGE_TYPE_DEFN_LOCAL(dahdichannel_type,
|
|||
);
|
||||
|
||||
/*! \brief Sends a DAHDIChannel channel blob used to produce DAHDIChannel AMI messages */
|
||||
static void publish_dahdichannel(struct ast_channel *chan, int span, const char *dahdi_channel)
|
||||
static void publish_dahdichannel(struct ast_channel *chan, ast_group_t group, int span, const char *dahdi_channel)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
|
||||
|
||||
ast_assert(dahdi_channel != NULL);
|
||||
|
||||
blob = ast_json_pack("{s: i, s: s}",
|
||||
blob = ast_json_pack("{s: I, s: i, s: s}",
|
||||
"group", (ast_json_int_t)group,
|
||||
"span", span,
|
||||
"channel", dahdi_channel);
|
||||
if (!blob) {
|
||||
|
@ -1793,7 +1812,7 @@ static void dahdi_ami_channel_event(struct dahdi_pvt *p, struct ast_channel *cha
|
|||
/* Real channel */
|
||||
snprintf(ch_name, sizeof(ch_name), "%d", p->channel);
|
||||
}
|
||||
publish_dahdichannel(chan, p->span, ch_name);
|
||||
publish_dahdichannel(chan, p->group, p->span, ch_name);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PRI
|
||||
|
@ -3532,6 +3551,21 @@ static void handle_clear_alarms(struct dahdi_pvt *p)
|
|||
}
|
||||
|
||||
#ifdef HAVE_OPENR2
|
||||
static void mfcr2_queue_for_destruction(const struct dahdi_pvt *p)
|
||||
{
|
||||
const struct dahdi_mfcr2 *r2link = p->mfcr2;
|
||||
struct r2link_entry *cur;
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
if (r2link == &cur->mfcr2) {
|
||||
ast_debug(3, "MFC/R2 channel %d queued for destruction\n", p->channel);
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
}
|
||||
|
||||
static int dahdi_r2_answer(struct dahdi_pvt *p)
|
||||
{
|
||||
|
@ -3617,6 +3651,9 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
|
|||
p->inalarm = alarm ? 1 : 0;
|
||||
if (p->inalarm) {
|
||||
res = get_alarms(p);
|
||||
if (res == DAHDI_ALARM_NOTOPEN) {
|
||||
mfcr2_queue_for_destruction(p);
|
||||
}
|
||||
handle_alarms(p, res);
|
||||
} else {
|
||||
handle_clear_alarms(p);
|
||||
|
@ -3626,7 +3663,19 @@ static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
|
|||
|
||||
static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
|
||||
{
|
||||
struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
|
||||
|
||||
ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
|
||||
ast_mutex_lock(&p->lock);
|
||||
/* Disconnected? */
|
||||
if (errorcode == ENODEV) {
|
||||
struct dahdi_mfcr2 *r2link = p->mfcr2;
|
||||
p->mfcr2call = 0;
|
||||
if (r2link) {
|
||||
r2link->nodev = 1;
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
}
|
||||
|
||||
static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
|
||||
|
@ -3829,6 +3878,7 @@ static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disco
|
|||
ast_copy_string(cause_code->code, cause_str, datalen + 1 - sizeof(*cause_code));
|
||||
ast_queue_control_data(p->owner, AST_CONTROL_PVT_CAUSE_CODE, cause_code, datalen);
|
||||
ast_channel_hangupcause_hash_set(p->owner, cause_code, datalen);
|
||||
ast_channel_hangupcause_set(p->owner, cause_code->ast_cause);
|
||||
|
||||
/* when we have an owner we don't call dahdi_r2_disconnect_call here, that will
|
||||
be done in dahdi_hangup */
|
||||
|
@ -5462,6 +5512,49 @@ static void dahdi_unlink_ss7_pvt(struct dahdi_pvt *pvt)
|
|||
}
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
|
||||
#if defined(HAVE_OPENR2)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Unlink the channel interface from the MFC/R2 private pointer array.
|
||||
*
|
||||
* \param pvt chan_dahdi private interface structure to unlink.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void dahdi_unlink_mfcr2_pvt(struct dahdi_pvt *pvt)
|
||||
{
|
||||
unsigned idx;
|
||||
struct dahdi_mfcr2 *mfcr2;
|
||||
int should_destroy_link = 0;
|
||||
|
||||
ast_mutex_lock(&pvt->lock);
|
||||
if (pvt->r2chan) {
|
||||
ast_debug(1, "Disable MFC/R2 channel %d read\n", pvt->channel);
|
||||
openr2_chan_disable_read(pvt->r2chan);
|
||||
}
|
||||
mfcr2 = pvt->mfcr2;
|
||||
if (mfcr2) {
|
||||
for (idx = 0; idx < mfcr2->numchans; ++idx) {
|
||||
if (mfcr2->pvts[idx] == pvt) {
|
||||
ast_debug(1, "Removing MFC/R2 channel %d from the mfcr2 link\n", pvt->channel);
|
||||
mfcr2->pvts[idx] = NULL;
|
||||
mfcr2->live_chans--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!mfcr2->live_chans) {
|
||||
ast_debug(1, "MFC/R2 link is now empty\n");
|
||||
should_destroy_link = 1;
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&pvt->lock);
|
||||
if (should_destroy_link) {
|
||||
ast_debug(1, "MFC/R2 link is now empty\n");
|
||||
mfcr2_queue_for_destruction(pvt);
|
||||
}
|
||||
}
|
||||
#endif /* defined(HAVE_OPENR2) */
|
||||
|
||||
static struct dahdi_pvt *find_next_iface_in_span(struct dahdi_pvt *cur)
|
||||
{
|
||||
if (cur->next && cur->next->span == cur->span) {
|
||||
|
@ -5490,6 +5583,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
|
|||
#endif /* defined(HAVE_PRI) */
|
||||
#if defined(HAVE_SS7)
|
||||
dahdi_unlink_ss7_pvt(p);
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
#if defined(HAVE_OPENR2)
|
||||
dahdi_unlink_mfcr2_pvt(p);
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
switch (pvt->which_iflist) {
|
||||
case DAHDI_IFLIST_NONE:
|
||||
|
@ -6692,6 +6788,10 @@ static int dahdi_func_read(struct ast_channel *chan, const char *function, char
|
|||
ast_mutex_lock(&p->lock);
|
||||
snprintf(buf, len, "%d", p->span);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
} else if (!strcasecmp(data, "dahdi_group")) {
|
||||
ast_mutex_lock(&p->lock);
|
||||
snprintf(buf, len, "%llu", p->group);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
} else if (!strcasecmp(data, "dahdi_type")) {
|
||||
ast_mutex_lock(&p->lock);
|
||||
switch (p->sig) {
|
||||
|
@ -7659,8 +7759,16 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
|
|||
c++;
|
||||
else
|
||||
c = p->dialdest;
|
||||
if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
|
||||
else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
|
||||
|
||||
if (*c) {
|
||||
int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
|
||||
if (numchars >= sizeof(p->dop.dialstr)) {
|
||||
ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
|
||||
}
|
||||
} else {
|
||||
ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
|
||||
}
|
||||
|
||||
if (strlen(p->dop.dialstr) > 4) {
|
||||
memset(p->echorest, 'w', sizeof(p->echorest) - 1);
|
||||
strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
|
||||
|
@ -10992,6 +11100,40 @@ static void dahdi_destroy_channel_range(int start, int end)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENR2
|
||||
static void dahdi_r2_destroy_nodev(void)
|
||||
{
|
||||
struct r2link_entry *cur;
|
||||
AST_LIST_LOCK(&nodev_r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&nodev_r2links, cur, list) {
|
||||
int i;
|
||||
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
||||
ast_debug(3, "About to destroy %d DAHDI channels of MFC/R2 link.\n", r2->numchans);
|
||||
for (i = 0; i < r2->numchans; i++) {
|
||||
int channel;
|
||||
struct dahdi_pvt *pvt = r2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
channel = pvt->channel;
|
||||
ast_debug(3, "About to destroy B-channel %d.\n", channel);
|
||||
dahdi_destroy_channel_range(channel, channel);
|
||||
}
|
||||
ast_debug(3, "Destroying R2 link\n");
|
||||
AST_LIST_REMOVE(&nodev_r2links, cur, list);
|
||||
if (r2->r2master != AST_PTHREADT_NULL) {
|
||||
pthread_cancel(r2->r2master);
|
||||
pthread_join(r2->r2master, NULL);
|
||||
r2->r2master = AST_PTHREADT_NULL;
|
||||
openr2_context_delete(r2->protocol_context);
|
||||
}
|
||||
ast_free(cur);
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&nodev_r2links);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int setup_dahdi(int reload);
|
||||
static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
|
||||
|
||||
|
@ -11615,6 +11757,9 @@ static void *do_monitor(void *data)
|
|||
}
|
||||
ast_mutex_unlock(&iflock);
|
||||
release_doomed_pris();
|
||||
#ifdef HAVE_OPENR2
|
||||
dahdi_r2_destroy_nodev();
|
||||
#endif
|
||||
}
|
||||
/* Never reached */
|
||||
pthread_cleanup_pop(1);
|
||||
|
@ -11800,55 +11945,70 @@ static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
|
|||
#ifdef HAVE_OPENR2
|
||||
static void dahdi_r2_destroy_links(void)
|
||||
{
|
||||
int i = 0;
|
||||
if (!r2links) {
|
||||
return;
|
||||
struct r2link_entry *cur;
|
||||
|
||||
/* Queue everything for removal */
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
ast_debug(3, "MFC/R2 link #%d queued for destruction\n", cur->mfcr2.index);
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
}
|
||||
for (; i < r2links_count; i++) {
|
||||
if (r2links[i]->r2master != AST_PTHREADT_NULL) {
|
||||
pthread_cancel(r2links[i]->r2master);
|
||||
pthread_join(r2links[i]->r2master, NULL);
|
||||
openr2_context_delete(r2links[i]->protocol_context);
|
||||
}
|
||||
ast_free(r2links[i]);
|
||||
}
|
||||
ast_free(r2links);
|
||||
r2links = NULL;
|
||||
r2links_count = 0;
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
/* Now destroy properly */
|
||||
dahdi_r2_destroy_nodev();
|
||||
}
|
||||
|
||||
/* This is an artificial convenient capacity, to keep at most a full E1 of channels in a single thread */
|
||||
#define R2_LINK_CAPACITY 30
|
||||
static struct dahdi_mfcr2 *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
|
||||
static struct r2link_entry *dahdi_r2_get_link(const struct dahdi_chan_conf *conf)
|
||||
{
|
||||
struct dahdi_mfcr2 *new_r2link = NULL;
|
||||
struct dahdi_mfcr2 **new_r2links = NULL;
|
||||
|
||||
struct r2link_entry *cur = NULL;
|
||||
/* Only create a new R2 link if
|
||||
1. This is the first link requested
|
||||
2. Configuration changed
|
||||
3. We got more channels than supported per link */
|
||||
if (!r2links_count ||
|
||||
memcmp(&conf->mfcr2, &r2links[r2links_count - 1]->conf, sizeof(conf->mfcr2)) ||
|
||||
(r2links[r2links_count - 1]->numchans == R2_LINK_CAPACITY)) {
|
||||
new_r2link = ast_calloc(1, sizeof(**r2links));
|
||||
if (!new_r2link) {
|
||||
ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
|
||||
return NULL;
|
||||
AST_LIST_LOCK(&r2links);
|
||||
if (! AST_LIST_EMPTY(&r2links)) {
|
||||
cur = AST_LIST_LAST(&r2links);
|
||||
if (memcmp(&conf->mfcr2, &cur->mfcr2.conf, sizeof(conf->mfcr2))) {
|
||||
ast_debug(3, "Need new R2 link because of: Configuration change\n");
|
||||
cur = NULL;
|
||||
} else if (cur->mfcr2.numchans == R2_LINK_CAPACITY) {
|
||||
ast_debug(3, "Need new R2 link because of: Capacity (%d)\n", R2_LINK_CAPACITY);
|
||||
cur = NULL;
|
||||
}
|
||||
new_r2links = ast_realloc(r2links, ((r2links_count + 1) * sizeof(*r2links)));
|
||||
if (!new_r2links) {
|
||||
ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
|
||||
ast_free(new_r2link);
|
||||
return NULL;
|
||||
}
|
||||
r2links = new_r2links;
|
||||
new_r2link->r2master = AST_PTHREADT_NULL;
|
||||
r2links[r2links_count] = new_r2link;
|
||||
r2links_count++;
|
||||
ast_debug(1, "Created new R2 link!\n");
|
||||
}
|
||||
return r2links[r2links_count - 1];
|
||||
if (!cur) {
|
||||
struct r2link_entry *tmp = NULL;
|
||||
int new_idx = r2links_count + 1;
|
||||
int i;
|
||||
for (i = 1; i <= r2links_count; i++) {
|
||||
int i_unused = 1;
|
||||
AST_LIST_TRAVERSE(&r2links, tmp, list) {
|
||||
if (i == tmp->mfcr2.index) {
|
||||
i_unused = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i_unused) {
|
||||
new_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur = ast_calloc(1, sizeof(*cur));
|
||||
if (!cur) {
|
||||
ast_log(LOG_ERROR, "Cannot allocate R2 link!\n");
|
||||
return NULL;
|
||||
}
|
||||
cur->mfcr2.index = new_idx;
|
||||
cur->mfcr2.r2master = AST_PTHREADT_NULL;
|
||||
r2links_count++;
|
||||
ast_debug(3, "Created new R2 link #%d (now have %d)\n", new_idx, r2links_count);
|
||||
AST_LIST_INSERT_TAIL(&r2links, cur, list);
|
||||
}
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_chan_conf *conf)
|
||||
|
@ -11903,7 +12063,7 @@ static int dahdi_r2_set_context(struct dahdi_mfcr2 *r2_link, const struct dahdi_
|
|||
}
|
||||
}
|
||||
/* Save the configuration used to setup this link */
|
||||
memcpy(&r2_link->conf, conf, sizeof(r2_link->conf));
|
||||
memcpy(&r2_link->conf, &conf->mfcr2, sizeof(r2_link->conf));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -12103,7 +12263,8 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
#ifdef HAVE_OPENR2
|
||||
if (chan_sig == SIG_MFCR2) {
|
||||
struct dahdi_mfcr2 *r2_link;
|
||||
r2_link = dahdi_r2_get_link(conf);
|
||||
struct r2link_entry *r2_le = dahdi_r2_get_link(conf);
|
||||
r2_link = &r2_le->mfcr2;
|
||||
if (!r2_link) {
|
||||
ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
|
||||
destroy_dahdi_pvt(tmp);
|
||||
|
@ -12129,6 +12290,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
destroy_dahdi_pvt(tmp);
|
||||
return NULL;
|
||||
}
|
||||
r2_link->live_chans++;
|
||||
tmp->mfcr2 = r2_link;
|
||||
if (conf->mfcr2.call_files) {
|
||||
openr2_chan_enable_call_files(tmp->r2chan);
|
||||
|
@ -12594,6 +12756,8 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
* knows that we care about it. Then, chan_dahdi will get the MWI from the
|
||||
* event cache instead of checking the mailbox directly. */
|
||||
tmp->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
|
||||
stasis_subscription_accept_message_type(tmp->mwi_event_sub, ast_mwi_state_type());
|
||||
stasis_subscription_set_filter(tmp->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
|
||||
|
@ -13695,6 +13859,8 @@ static void dahdi_ss7_error(struct ss7 *ss7, char *s)
|
|||
static void *mfcr2_monitor(void *data)
|
||||
{
|
||||
struct dahdi_mfcr2 *mfcr2 = data;
|
||||
struct dahdi_pvt *pvt;
|
||||
|
||||
/* we should be using pthread_key_create
|
||||
and allocate pollers dynamically.
|
||||
I think do_monitor() could be leaking, since it
|
||||
|
@ -13711,8 +13877,12 @@ static void *mfcr2_monitor(void *data)
|
|||
/* now that we're ready to get calls, unblock our side and
|
||||
get current line state */
|
||||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
openr2_chan_set_idle(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
openr2_chan_set_idle(pvt->r2chan);
|
||||
openr2_chan_handle_cas(pvt->r2chan);
|
||||
}
|
||||
while (1) {
|
||||
/* we trust here that the mfcr2 channel list will not ever change once
|
||||
|
@ -13721,17 +13891,24 @@ static void *mfcr2_monitor(void *data)
|
|||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
pollers[i].revents = 0;
|
||||
pollers[i].events = 0;
|
||||
if (mfcr2->pvts[i]->owner) {
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
if (!mfcr2->pvts[i]->r2chan) {
|
||||
ast_debug(1, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
|
||||
if (pvt->owner) {
|
||||
continue;
|
||||
}
|
||||
if (mfcr2->nodev) {
|
||||
continue;
|
||||
}
|
||||
if (!pvt->r2chan) {
|
||||
ast_debug(1, "Wow, no r2chan on channel %d\n", pvt->channel);
|
||||
quit_loop = 1;
|
||||
break;
|
||||
}
|
||||
openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_enable_read(pvt->r2chan);
|
||||
pollers[i].events = POLLIN | POLLPRI;
|
||||
pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
|
||||
pollers[i].fd = pvt->subs[SUB_REAL].dfd;
|
||||
pollsize++;
|
||||
}
|
||||
if (quit_loop) {
|
||||
|
@ -13758,8 +13935,12 @@ static void *mfcr2_monitor(void *data)
|
|||
/* do we want to allow to cancel while processing events? */
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
|
||||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
pvt = mfcr2->pvts[i];
|
||||
if (!pvt) {
|
||||
continue;
|
||||
}
|
||||
if (pollers[i].revents & POLLPRI || pollers[i].revents & POLLIN) {
|
||||
openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
|
||||
openr2_chan_process_event(pvt->r2chan);
|
||||
}
|
||||
}
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
|
||||
|
@ -14688,10 +14869,11 @@ static char *handle_mfcr2_show_variants(struct ast_cli_entry *e, int cmd, struct
|
|||
|
||||
static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
#define FORMAT "%4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
|
||||
#define FORMAT "%4s %4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
|
||||
int filtertype = 0;
|
||||
int targetnum = 0;
|
||||
char channo[5];
|
||||
char linkno[5];
|
||||
char anino[5];
|
||||
char dnisno[5];
|
||||
struct dahdi_pvt *p;
|
||||
|
@ -14723,7 +14905,7 @@ static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct
|
|||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
}
|
||||
ast_cli(a->fd, FORMAT, "Chan", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
|
||||
ast_cli(a->fd, FORMAT, "Chan", "Link#", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
|
||||
ast_mutex_lock(&iflock);
|
||||
for (p = iflist; p; p = p->next) {
|
||||
if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
|
||||
|
@ -14748,9 +14930,10 @@ static char *handle_mfcr2_show_channels(struct ast_cli_entry *e, int cmd, struct
|
|||
r2context = openr2_chan_get_context(p->r2chan);
|
||||
r2variant = openr2_context_get_variant(r2context);
|
||||
snprintf(channo, sizeof(channo), "%d", p->channel);
|
||||
snprintf(linkno, sizeof(linkno), "%d", p->mfcr2->index);
|
||||
snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
|
||||
snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
|
||||
ast_cli(a->fd, FORMAT, channo, openr2_proto_get_variant_string(r2variant),
|
||||
ast_cli(a->fd, FORMAT, channo, linkno, openr2_proto_get_variant_string(r2variant),
|
||||
anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",
|
||||
openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
|
||||
openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
|
||||
|
@ -14961,14 +15144,163 @@ static char *handle_mfcr2_set_blocked(struct ast_cli_entry *e, int cmd, struct a
|
|||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static void mfcr2_show_links_of(struct ast_cli_args *a, struct r2links *list_head, const char *title)
|
||||
{
|
||||
#define FORMAT "%-5s %-10s %-15s %-10s %s\n"
|
||||
AST_LIST_LOCK(list_head);
|
||||
if (! AST_LIST_EMPTY(list_head)) {
|
||||
int x = 0;
|
||||
char index[5];
|
||||
char live_chans_str[5];
|
||||
char channel_list[R2_LINK_CAPACITY * 4];
|
||||
struct r2link_entry *cur;
|
||||
ast_cli(a->fd, "%s\n", title);
|
||||
ast_cli(a->fd, FORMAT, "Index", "Thread", "Dahdi-Device", "Channels", "Channel-List");
|
||||
AST_LIST_TRAVERSE(list_head, cur, list) {
|
||||
struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
|
||||
const char *thread_status = NULL;
|
||||
int i;
|
||||
int len;
|
||||
int inside_range;
|
||||
int channo;
|
||||
int prev_channo;
|
||||
x++;
|
||||
if (mfcr2->r2master == 0L) {
|
||||
thread_status = "zero";
|
||||
} else if (mfcr2->r2master == AST_PTHREADT_NULL) {
|
||||
thread_status = "none";
|
||||
} else {
|
||||
thread_status = "created";
|
||||
}
|
||||
snprintf(index, sizeof(index), "%d", mfcr2->index);
|
||||
snprintf(live_chans_str, sizeof(live_chans_str), "%d", mfcr2->live_chans);
|
||||
channo = 0;
|
||||
prev_channo = 0;
|
||||
inside_range = 0;
|
||||
len = 0;
|
||||
/* Prepare nice string in channel_list[] */
|
||||
for (i = 0; i < mfcr2->numchans; i++) {
|
||||
struct dahdi_pvt *p = mfcr2->pvts[i];
|
||||
if (!p) {
|
||||
continue;
|
||||
}
|
||||
channo = p->channel;
|
||||
/* Don't show a range until we know the last channel number */
|
||||
if (prev_channo && prev_channo == channo - 1) {
|
||||
prev_channo = channo;
|
||||
inside_range = 1;
|
||||
continue;
|
||||
}
|
||||
if (inside_range) {
|
||||
/* Close range */
|
||||
len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d,%d", prev_channo, channo);
|
||||
inside_range = 0;
|
||||
} else if (prev_channo) {
|
||||
/* Non-sequential channel numbers */
|
||||
len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
|
||||
} else {
|
||||
/* First channel number */
|
||||
len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "%d", channo);
|
||||
}
|
||||
prev_channo = channo;
|
||||
}
|
||||
/* Handle leftover channels */
|
||||
if (inside_range) {
|
||||
/* Close range */
|
||||
len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, "-%d", channo);
|
||||
inside_range = 0;
|
||||
} else if (prev_channo) {
|
||||
/* Non-sequential channel numbers */
|
||||
len += snprintf(channel_list + len, sizeof(channel_list) - len - 1, ",%d", channo);
|
||||
}
|
||||
// channel_list[len] = '\0';
|
||||
ast_cli(a->fd, FORMAT,
|
||||
index,
|
||||
thread_status,
|
||||
(mfcr2->nodev) ? "MISSING" : "OK",
|
||||
live_chans_str,
|
||||
channel_list);
|
||||
}
|
||||
}
|
||||
AST_LIST_UNLOCK(list_head);
|
||||
#undef FORMAT
|
||||
}
|
||||
|
||||
static char *handle_mfcr2_show_links(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "mfcr2 show links";
|
||||
e->usage =
|
||||
"Usage: mfcr2 show links\n"
|
||||
" Shows the DAHDI MFC/R2 links.\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
if (a->argc != 3) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
mfcr2_show_links_of(a, &r2links, "Live links\n");
|
||||
mfcr2_show_links_of(a, &nodev_r2links, "Links to be removed (device missing)\n");
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static char *handle_mfcr2_destroy_link(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
int res;
|
||||
int wanted_link_index;
|
||||
int found_link = 0;
|
||||
struct r2link_entry *cur = NULL;
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "mfcr2 destroy link";
|
||||
e->usage =
|
||||
"Usage: mfcr2 destroy link <index-number>\n"
|
||||
" Destorys D-channel of link and its B-channels.\n"
|
||||
" DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
}
|
||||
if (a->argc < 4) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
res = sscanf(a->argv[3], "%30d", &wanted_link_index);
|
||||
if ((res != 1) || wanted_link_index < 1) {
|
||||
ast_cli(a->fd,
|
||||
"Invalid link index '%s'. Should be a positive number\n", a->argv[3]);
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&r2links, cur, list) {
|
||||
struct dahdi_mfcr2 *mfcr2 = &cur->mfcr2;
|
||||
if (wanted_link_index == mfcr2->index) {
|
||||
AST_LIST_MOVE_CURRENT(&nodev_r2links, list);
|
||||
r2links_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
if (! found_link) {
|
||||
ast_cli(a->fd, "No link found with index %d.\n", wanted_link_index);
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry dahdi_mfcr2_cli[] = {
|
||||
AST_CLI_DEFINE(handle_mfcr2_version, "Show OpenR2 library version"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_show_variants, "Show supported MFC/R2 variants"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_show_channels, "Show MFC/R2 channels"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_show_links, "Show MFC/R2 links"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_set_debug, "Set MFC/R2 channel logging level"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED"),
|
||||
AST_CLI_DEFINE(handle_mfcr2_destroy_link, "Destroy given MFC/R2 link"),
|
||||
};
|
||||
|
||||
#endif /* HAVE_OPENR2 */
|
||||
|
@ -19271,15 +19603,22 @@ static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, str
|
|||
#endif /* defined(HAVE_SS7) */
|
||||
#ifdef HAVE_OPENR2
|
||||
if (reload != 1) {
|
||||
int x;
|
||||
for (x = 0; x < r2links_count; x++) {
|
||||
if (ast_pthread_create(&r2links[x]->r2master, NULL, mfcr2_monitor, r2links[x])) {
|
||||
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
||||
return -1;
|
||||
} else {
|
||||
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
||||
struct r2link_entry *cur;
|
||||
int x = 0;
|
||||
AST_LIST_LOCK(&r2links);
|
||||
AST_LIST_TRAVERSE(&r2links, cur, list) {
|
||||
struct dahdi_mfcr2 *r2 = &cur->mfcr2;
|
||||
if (r2->r2master == AST_PTHREADT_NULL) {
|
||||
if (ast_pthread_create(&r2->r2master, NULL, mfcr2_monitor, r2)) {
|
||||
ast_log(LOG_ERROR, "Unable to start R2 monitor on channel group %d\n", x + 1);
|
||||
return -1;
|
||||
} else {
|
||||
ast_verb(2, "Starting R2 monitor on channel group %d\n", x + 1);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
}
|
||||
AST_LIST_UNLOCK(&r2links);
|
||||
}
|
||||
#endif
|
||||
/* And start the monitor for the first time */
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "asterisk/channel.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
#include "asterisk/manager.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/features.h"
|
||||
|
@ -1456,6 +1457,8 @@ static void network_change_stasis_subscribe(void)
|
|||
if (!network_change_sub) {
|
||||
network_change_sub = stasis_subscribe(ast_system_topic(),
|
||||
network_change_stasis_cb, NULL);
|
||||
stasis_subscription_accept_message_type(network_change_sub, ast_network_change_type());
|
||||
stasis_subscription_set_filter(network_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1469,6 +1472,8 @@ static void acl_change_stasis_subscribe(void)
|
|||
if (!acl_change_sub) {
|
||||
acl_change_sub = stasis_subscribe(ast_security_topic(),
|
||||
acl_change_stasis_cb, NULL);
|
||||
stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
|
||||
stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3809,7 +3814,7 @@ static int peer_status(struct iax2_peer *peer, char *status, int statuslen)
|
|||
/*! \brief Show one peer in detail */
|
||||
static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
char status[30];
|
||||
char status[64];
|
||||
char cbuf[256];
|
||||
struct iax2_peer *peer;
|
||||
struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
|
||||
|
@ -6831,7 +6836,7 @@ struct show_peers_context {
|
|||
static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers_context *cont, struct iax2_peer *peer)
|
||||
{
|
||||
char name[256] = "";
|
||||
char status[20];
|
||||
char status[64];
|
||||
int retstatus;
|
||||
struct ast_str *encmethods = ast_str_alloca(256);
|
||||
|
||||
|
@ -11106,18 +11111,18 @@ static int socket_process_helper(struct iax2_thread *thread)
|
|||
if (iaxs[fr->callno]->pingtime <= peer->maxms) {
|
||||
ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %u\n", peer->name, iaxs[fr->callno]->pingtime);
|
||||
ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"peer_status", "Reachable",
|
||||
"time", iaxs[fr->callno]->pingtime);
|
||||
"time", (ast_json_int_t)iaxs[fr->callno]->pingtime);
|
||||
ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
|
||||
}
|
||||
} else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
|
||||
if (iaxs[fr->callno]->pingtime > peer->maxms) {
|
||||
ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%u ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
|
||||
ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
|
||||
blob = ast_json_pack("{s: s, s: i}",
|
||||
blob = ast_json_pack("{s: s, s: I}",
|
||||
"peer_status", "Lagged",
|
||||
"time", iaxs[fr->callno]->pingtime);
|
||||
"time", (ast_json_int_t)iaxs[fr->callno]->pingtime);
|
||||
ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */
|
||||
}
|
||||
}
|
||||
|
@ -13072,6 +13077,8 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
|
|||
* mailboxes. However, we just grab the events out of the cache when it
|
||||
* is time to send MWI, since it is only sent with a REGACK. */
|
||||
peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
|
||||
stasis_subscription_accept_message_type(peer->mwi_event_sub, ast_mwi_state_type());
|
||||
stasis_subscription_set_filter(peer->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14708,23 +14715,54 @@ static int load_objects(void)
|
|||
peers = users = iax_peercallno_pvts = iax_transfercallno_pvts = NULL;
|
||||
peercnts = callno_limits = calltoken_ignores = NULL;
|
||||
|
||||
if (!(peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb))) {
|
||||
peers = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_PEER_BUCKETS,
|
||||
peer_hash_cb, NULL, peer_cmp_cb);
|
||||
if (!peers) {
|
||||
goto container_fail;
|
||||
} else if (!(users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb))) {
|
||||
}
|
||||
|
||||
users = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_USER_BUCKETS,
|
||||
user_hash_cb, NULL, user_cmp_cb);
|
||||
if (!users) {
|
||||
goto container_fail;
|
||||
} else if (!(iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb))) {
|
||||
}
|
||||
|
||||
iax_peercallno_pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
IAX_MAX_CALLS, pvt_hash_cb, NULL, pvt_cmp_cb);
|
||||
if (!iax_peercallno_pvts) {
|
||||
goto container_fail;
|
||||
} else if (!(iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb))) {
|
||||
}
|
||||
|
||||
iax_transfercallno_pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
IAX_MAX_CALLS, transfercallno_pvt_hash_cb, NULL, transfercallno_pvt_cmp_cb);
|
||||
if (!iax_transfercallno_pvts) {
|
||||
goto container_fail;
|
||||
} else if (!(peercnts = ao2_container_alloc(MAX_PEER_BUCKETS, peercnt_hash_cb, peercnt_cmp_cb))) {
|
||||
}
|
||||
|
||||
peercnts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_PEER_BUCKETS,
|
||||
peercnt_hash_cb, NULL, peercnt_cmp_cb);
|
||||
if (!peercnts) {
|
||||
goto container_fail;
|
||||
} else if (!(callno_limits = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
|
||||
}
|
||||
|
||||
callno_limits = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
MAX_PEER_BUCKETS, addr_range_hash_cb, NULL, addr_range_cmp_cb);
|
||||
if (!callno_limits) {
|
||||
goto container_fail;
|
||||
} else if (!(calltoken_ignores = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
|
||||
}
|
||||
|
||||
calltoken_ignores = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
MAX_PEER_BUCKETS, addr_range_hash_cb, NULL, addr_range_cmp_cb);
|
||||
if (!calltoken_ignores) {
|
||||
goto container_fail;
|
||||
} else if (create_callno_pools()) {
|
||||
}
|
||||
|
||||
if (create_callno_pools()) {
|
||||
goto container_fail;
|
||||
} else if (!(transmit_processor = ast_taskprocessor_get("iax2_transmit", TPS_REF_DEFAULT))) {
|
||||
}
|
||||
|
||||
transmit_processor = ast_taskprocessor_get("iax2_transmit", TPS_REF_DEFAULT);
|
||||
if (!transmit_processor) {
|
||||
goto container_fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/features.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
|
@ -4242,6 +4243,8 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
|
|||
* knows that we care about it. Then, chan_mgcp will get the MWI from the
|
||||
* event cache instead of checking the mailbox directly. */
|
||||
e->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
|
||||
stasis_subscription_accept_message_type(e->mwi_event_sub, ast_mwi_state_type());
|
||||
stasis_subscription_set_filter(e->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", (unsigned long)ast_random());
|
||||
|
|
|
@ -471,7 +471,9 @@ static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
|
||||
state->sessions = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
SESSION_BUCKETS, jingle_session_hash, NULL, jingle_session_cmp);
|
||||
if (!state->sessions) {
|
||||
ao2_ref(state, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -601,7 +603,9 @@ static void *jingle_config_alloc(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
|
||||
cfg->endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
|
||||
ENDPOINT_BUCKETS, jingle_endpoint_hash, NULL, jingle_endpoint_cmp);
|
||||
if (!cfg->endpoints) {
|
||||
ao2_ref(cfg, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
/*** MODULEINFO
|
||||
<depend>pjproject</depend>
|
||||
<depend>res_pjsip</depend>
|
||||
<depend>res_pjsip_pubsub</depend>
|
||||
<depend>res_pjsip_session</depend>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
@ -748,7 +749,8 @@ static int chan_pjsip_answer(struct ast_channel *ast)
|
|||
}
|
||||
|
||||
/*! \brief Internal helper function called when CNG tone is detected */
|
||||
static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *session, struct ast_frame *f)
|
||||
static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_channel *ast, struct ast_sip_session *session,
|
||||
struct ast_frame *f)
|
||||
{
|
||||
const char *target_context;
|
||||
int exists;
|
||||
|
@ -764,11 +766,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
|
|||
}
|
||||
|
||||
/* If already executing in the fax extension don't do anything */
|
||||
if (!strcmp(ast_channel_exten(session->channel), "fax")) {
|
||||
if (!strcmp(ast_channel_exten(ast), "fax")) {
|
||||
return f;
|
||||
}
|
||||
|
||||
target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel));
|
||||
target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
|
||||
|
||||
/*
|
||||
* We need to unlock the channel here because ast_exists_extension has the
|
||||
|
@ -777,25 +779,30 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
|
|||
*
|
||||
* ast_async_goto() has its own restriction on not holding the channel lock.
|
||||
*/
|
||||
ast_channel_unlock(session->channel);
|
||||
ast_channel_unlock(ast);
|
||||
ast_frfree(f);
|
||||
f = &ast_null_frame;
|
||||
exists = ast_exists_extension(session->channel, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(session->channel)->id.number.valid,
|
||||
ast_channel_caller(session->channel)->id.number.str, NULL));
|
||||
exists = ast_exists_extension(ast, target_context, "fax", 1,
|
||||
S_COR(ast_channel_caller(ast)->id.number.valid,
|
||||
ast_channel_caller(ast)->id.number.str, NULL));
|
||||
if (exists) {
|
||||
ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n",
|
||||
ast_channel_name(session->channel));
|
||||
pbx_builtin_setvar_helper(session->channel, "FAXEXTEN", ast_channel_exten(session->channel));
|
||||
if (ast_async_goto(session->channel, target_context, "fax", 1)) {
|
||||
ast_channel_name(ast));
|
||||
pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
|
||||
if (ast_async_goto(ast, target_context, "fax", 1)) {
|
||||
ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n",
|
||||
ast_channel_name(session->channel), target_context);
|
||||
ast_channel_name(ast), target_context);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n",
|
||||
ast_channel_name(session->channel), target_context);
|
||||
ast_channel_name(ast), target_context);
|
||||
}
|
||||
ast_channel_lock(session->channel);
|
||||
|
||||
/* It's possible for a masquerade to have occurred when doing the ast_async_goto resulting in
|
||||
* the channel on the session having changed. Since we need to return with the original channel
|
||||
* locked we lock the channel that was passed in and not session->channel.
|
||||
*/
|
||||
ast_channel_lock(ast);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
@ -894,7 +901,11 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
|
|||
if (f->subclass.integer == 'f') {
|
||||
ast_debug(3, "Channel driver fax CNG detected on %s\n",
|
||||
ast_channel_name(ast));
|
||||
f = chan_pjsip_cng_tone_detected(session, f);
|
||||
f = chan_pjsip_cng_tone_detected(ast, session, f);
|
||||
/* When chan_pjsip_cng_tone_detected returns it is possible for the
|
||||
* channel pointed to by ast and by session->channel to differ due to a
|
||||
* masquerade. It's best not to touch things after this.
|
||||
*/
|
||||
} else {
|
||||
ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer,
|
||||
ast_channel_name(ast));
|
||||
|
@ -1380,7 +1391,8 @@ static int is_colp_update_allowed(struct ast_sip_session *session)
|
|||
struct ast_party_id connected_id;
|
||||
int update_allowed = 0;
|
||||
|
||||
if (!session->endpoint->id.send_pai && !session->endpoint->id.send_rpid) {
|
||||
if (!session->endpoint->send_connected_line
|
||||
|| (!session->endpoint->id.send_pai && !session->endpoint->id.send_rpid)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1591,7 +1603,9 @@ static int chan_pjsip_indicate(struct ast_channel *ast, int condition, const voi
|
|||
switch (condition) {
|
||||
case AST_CONTROL_RINGING:
|
||||
if (ast_channel_state(ast) == AST_STATE_RING) {
|
||||
if (channel->session->endpoint->inband_progress) {
|
||||
if (channel->session->endpoint->inband_progress ||
|
||||
(channel->session->inv_session && channel->session->inv_session->neg &&
|
||||
pjmedia_sdp_neg_get_state(channel->session->inv_session->neg) == PJMEDIA_SDP_NEG_STATE_DONE)) {
|
||||
response_code = 183;
|
||||
res = -1;
|
||||
} else {
|
||||
|
@ -1891,6 +1905,130 @@ static void transfer_redirect(struct ast_sip_session *session, const char *targe
|
|||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
||||
}
|
||||
|
||||
/*! \brief REFER Callback module, used to attach session data structure to subscription */
|
||||
static pjsip_module refer_callback_module = {
|
||||
.name = { "REFER Callback", 14 },
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Callback function to report status of implicit REFER-NOTIFY subscription.
|
||||
*
|
||||
* This function will be called on any state change in the REFER-NOTIFY subscription.
|
||||
* Its primary purpose is to report SUCCESS/FAILURE of a transfer initiated via
|
||||
* \ref transfer_refer as well as to terminate the subscription, if necessary.
|
||||
*/
|
||||
static void xfer_client_on_evsub_state(pjsip_evsub *sub, pjsip_event *event)
|
||||
{
|
||||
struct ast_sip_session *session;
|
||||
struct ast_channel *chan = NULL;
|
||||
enum ast_control_transfer message = AST_TRANSFER_SUCCESS;
|
||||
int res = 0;
|
||||
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
session = pjsip_evsub_get_mod_data(sub, refer_callback_module.id);
|
||||
if (!session) {
|
||||
return;
|
||||
}
|
||||
|
||||
chan = session->channel;
|
||||
if (!chan) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
|
||||
/* Check if subscription is suppressed and terminate and send completion code, if so. */
|
||||
pjsip_rx_data *rdata;
|
||||
pjsip_generic_string_hdr *refer_sub;
|
||||
const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
|
||||
|
||||
ast_debug(3, "Transfer accepted on channel %s\n", ast_channel_name(chan));
|
||||
|
||||
/* Check if response message */
|
||||
if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
|
||||
rdata = event->body.tsx_state.src.rdata;
|
||||
|
||||
/* Find Refer-Sub header */
|
||||
refer_sub = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &REFER_SUB, NULL);
|
||||
|
||||
/* Check if subscription is suppressed. If it is, the far end will not terminate it,
|
||||
* and the subscription will remain active until it times out. Terminating it here
|
||||
* eliminates the unnecessary timeout.
|
||||
*/
|
||||
if (refer_sub && !pj_stricmp2(&refer_sub->hvalue, "false")) {
|
||||
/* Since no subscription is desired, assume that call has been transferred successfully. */
|
||||
/* Terminate subscription. */
|
||||
pjsip_evsub_terminate(sub, PJ_TRUE);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
} else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
|
||||
pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
|
||||
/* Check for NOTIFY complete or error. */
|
||||
pjsip_msg *msg;
|
||||
pjsip_msg_body *body;
|
||||
pjsip_status_line status_line = { .code = PJSIP_SC_NULL };
|
||||
pj_bool_t is_last;
|
||||
pj_status_t status;
|
||||
|
||||
if (event->type == PJSIP_EVENT_TSX_STATE && event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
|
||||
pjsip_rx_data *rdata;
|
||||
|
||||
rdata = event->body.tsx_state.src.rdata;
|
||||
msg = rdata->msg_info.msg;
|
||||
|
||||
if (!pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method())) {
|
||||
body = msg->body;
|
||||
if (body && !pj_stricmp2(&body->content_type.type, "message")
|
||||
&& !pj_stricmp2(&body->content_type.subtype, "sipfrag")) {
|
||||
pjsip_parse_status_line((char *)body->data, body->len, &status_line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status_line.code = 500;
|
||||
status_line.reason = *pjsip_get_status_text(500);
|
||||
}
|
||||
|
||||
is_last = (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED);
|
||||
/* If the status code is >= 200, the subscription is finished. */
|
||||
if (status_line.code >= 200 || is_last) {
|
||||
res = -1;
|
||||
|
||||
/* If the subscription has terminated, return AST_TRANSFER_SUCCESS for 2XX.
|
||||
* Any other status code returns AST_TRANSFER_FAILED.
|
||||
* The subscription should not terminate for any code < 200,
|
||||
* but if it does, that constitutes a failure. */
|
||||
if (status_line.code < 200 || status_line.code >= 300) {
|
||||
message = AST_TRANSFER_FAILED;
|
||||
}
|
||||
/* If subscription not terminated and subscription is finished (status code >= 200)
|
||||
* terminate it */
|
||||
if (!is_last) {
|
||||
pjsip_tx_data *tdata;
|
||||
|
||||
status = pjsip_evsub_initiate(sub, pjsip_get_subscribe_method(), 0, &tdata);
|
||||
if (status == PJ_SUCCESS) {
|
||||
pjsip_evsub_send_request(sub, tdata);
|
||||
}
|
||||
}
|
||||
/* Finished. Remove session from subscription */
|
||||
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, NULL);
|
||||
ast_debug(3, "Transfer channel %s completed: %d %.*s (%s)\n",
|
||||
ast_channel_name(chan),
|
||||
status_line.code,
|
||||
(int)status_line.reason.slen, status_line.reason.ptr,
|
||||
(message == AST_TRANSFER_SUCCESS) ? "Success" : "Failure");
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_refer(struct ast_sip_session *session, const char *target)
|
||||
{
|
||||
pjsip_evsub *sub;
|
||||
|
@ -1899,14 +2037,20 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
|
|||
pjsip_tx_data *packet;
|
||||
const char *ref_by_val;
|
||||
char local_info[pj_strlen(&session->inv_session->dlg->local.info_str) + 1];
|
||||
struct pjsip_evsub_user xfer_cb;
|
||||
|
||||
if (pjsip_xfer_create_uac(session->inv_session->dlg, NULL, &sub) != PJ_SUCCESS) {
|
||||
pj_bzero(&xfer_cb, sizeof(xfer_cb));
|
||||
xfer_cb.on_evsub_state = &xfer_client_on_evsub_state;
|
||||
|
||||
if (pjsip_xfer_create_uac(session->inv_session->dlg, &xfer_cb, &sub) != PJ_SUCCESS) {
|
||||
message = AST_TRANSFER_FAILED;
|
||||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pjsip_evsub_set_mod_data(sub, refer_callback_module.id, session);
|
||||
|
||||
if (pjsip_xfer_initiate(sub, pj_cstr(&tmp, target), &packet) != PJ_SUCCESS) {
|
||||
message = AST_TRANSFER_FAILED;
|
||||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
||||
|
@ -1924,7 +2068,6 @@ static void transfer_refer(struct ast_sip_session *session, const char *target)
|
|||
}
|
||||
|
||||
pjsip_xfer_send_request(sub, packet);
|
||||
ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message));
|
||||
}
|
||||
|
||||
static int transfer(void *data)
|
||||
|
@ -2021,7 +2164,7 @@ static int chan_pjsip_digit_begin(struct ast_channel *chan, char digit)
|
|||
break;
|
||||
case AST_SIP_DTMF_AUTO_INFO:
|
||||
if (!media || !media->rtp || (ast_rtp_instance_dtmf_mode_get(media->rtp) == AST_RTP_DTMF_MODE_NONE)) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
ast_rtp_instance_dtmf_begin(media->rtp, digit);
|
||||
break;
|
||||
|
@ -2339,18 +2482,27 @@ static int hangup(void *data)
|
|||
struct hangup_data *h_data = data;
|
||||
struct ast_channel *ast = h_data->chan;
|
||||
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
|
||||
struct ast_sip_session *session = channel->session;
|
||||
int cause = h_data->cause;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* afterwards.
|
||||
* Before cleaning we have to ensure that channel or its session is not NULL
|
||||
* we have seen rare case when taskprocessor calls hangup but channel is NULL
|
||||
* due to SIP session timeout and answer happening at the same time
|
||||
*/
|
||||
ast_sip_session_terminate(ao2_bump(session), cause);
|
||||
clear_session_and_channel(session, ast);
|
||||
ao2_cleanup(session);
|
||||
ao2_cleanup(channel);
|
||||
if (channel) {
|
||||
struct ast_sip_session *session = channel->session;
|
||||
if (session) {
|
||||
int cause = h_data->cause;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* afterwards.
|
||||
*/
|
||||
ast_sip_session_terminate(ao2_bump(session), cause);
|
||||
clear_session_and_channel(session, ast);
|
||||
ao2_cleanup(session);
|
||||
}
|
||||
ao2_cleanup(channel);
|
||||
}
|
||||
ao2_cleanup(h_data);
|
||||
return 0;
|
||||
}
|
||||
|
@ -3019,7 +3171,14 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct
|
|||
ast_channel_unlock(session->channel);
|
||||
break;
|
||||
case 183:
|
||||
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
|
||||
if (session->endpoint->ignore_183_without_sdp) {
|
||||
pjsip_rdata_sdp_info *sdp = pjsip_rdata_get_sdp_info(rdata);
|
||||
if (sdp && sdp->body.ptr) {
|
||||
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
} else {
|
||||
ast_queue_control(session->channel, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
break;
|
||||
case 200:
|
||||
ast_queue_control(session->channel, AST_CONTROL_ANSWER);
|
||||
|
@ -3051,6 +3210,11 @@ static struct ast_custom_function chan_pjsip_dial_contacts_function = {
|
|||
.read = pjsip_acf_dial_contacts_read,
|
||||
};
|
||||
|
||||
static struct ast_custom_function chan_pjsip_parse_uri_function = {
|
||||
.name = "PJSIP_PARSE_URI",
|
||||
.read = pjsip_acf_parse_uri_read,
|
||||
};
|
||||
|
||||
static struct ast_custom_function media_offer_function = {
|
||||
.name = "PJSIP_MEDIA_OFFER",
|
||||
.read = pjsip_acf_media_offer_read,
|
||||
|
@ -3100,6 +3264,11 @@ static int load_module(void)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (ast_custom_function_register(&chan_pjsip_parse_uri_function)) {
|
||||
ast_log(LOG_ERROR, "Unable to register PJSIP_PARSE_URI dialplan function\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ast_custom_function_register(&media_offer_function)) {
|
||||
ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
|
||||
goto end;
|
||||
|
@ -3115,6 +3284,8 @@ static int load_module(void)
|
|||
goto end;
|
||||
}
|
||||
|
||||
ast_sip_register_service(&refer_callback_module);
|
||||
|
||||
ast_sip_session_register_supplement(&chan_pjsip_supplement);
|
||||
ast_sip_session_register_supplement(&chan_pjsip_supplement_response);
|
||||
|
||||
|
@ -3151,9 +3322,11 @@ end:
|
|||
ast_sip_session_unregister_supplement(&chan_pjsip_supplement_response);
|
||||
ast_sip_session_unregister_supplement(&chan_pjsip_supplement);
|
||||
ast_sip_session_unregister_supplement(&call_pickup_supplement);
|
||||
ast_sip_unregister_service(&refer_callback_module);
|
||||
ast_custom_function_unregister(&dtmf_mode_function);
|
||||
ast_custom_function_unregister(&media_offer_function);
|
||||
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_channel_unregister(&chan_pjsip_tech);
|
||||
ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
|
||||
|
@ -3175,9 +3348,12 @@ static int unload_module(void)
|
|||
ast_sip_session_unregister_supplement(&chan_pjsip_ack_supplement);
|
||||
ast_sip_session_unregister_supplement(&call_pickup_supplement);
|
||||
|
||||
ast_sip_unregister_service(&refer_callback_module);
|
||||
|
||||
ast_custom_function_unregister(&dtmf_mode_function);
|
||||
ast_custom_function_unregister(&media_offer_function);
|
||||
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_channel_unregister(&chan_pjsip_tech);
|
||||
|
@ -3192,5 +3368,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Channel Driver"
|
|||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
|
||||
.requires = "res_pjsip,res_pjsip_session",
|
||||
.requires = "res_pjsip,res_pjsip_session,res_pjsip_pubsub",
|
||||
);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "asterisk/causes.h"
|
||||
#include "asterisk/format_cache.h"
|
||||
#include "asterisk/multicast_rtp.h"
|
||||
#include "asterisk/dns_core.h"
|
||||
|
||||
/* Forward declarations */
|
||||
static struct ast_channel *multicast_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);
|
||||
|
@ -293,9 +294,23 @@ static struct ast_channel *unicast_rtp_request(const char *type, struct ast_form
|
|||
ast_log(LOG_ERROR, "Destination is required for the 'UnicastRTP' channel\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (!ast_sockaddr_parse(&address, args.destination, PARSE_PORT_REQUIRE)) {
|
||||
ast_log(LOG_ERROR, "Destination '%s' could not be parsed\n", args.destination);
|
||||
goto failure;
|
||||
int rc;
|
||||
char *host;
|
||||
char *port;
|
||||
|
||||
rc = ast_sockaddr_split_hostport(args.destination, &host, &port, PARSE_PORT_REQUIRE);
|
||||
if (!rc) {
|
||||
ast_log(LOG_ERROR, "Unable to parse destination '%s' into host and port\n", args.destination);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
rc = ast_dns_resolve_ipv6_and_ipv4(&address, host, port);
|
||||
if (rc != 0) {
|
||||
ast_log(LOG_ERROR, "Unable to resolve host '%s'\n", host);
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args.options)
|
||||
|
|
|
@ -278,7 +278,7 @@
|
|||
#include "sip/include/security_events.h"
|
||||
#include "sip/include/route.h"
|
||||
#include "asterisk/sip_api.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/stasis.h"
|
||||
#include "asterisk/stasis_endpoints.h"
|
||||
|
@ -1815,8 +1815,9 @@ static int initialize_escs(void)
|
|||
{
|
||||
int i, res = 0;
|
||||
for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
|
||||
if (!((event_state_compositors[i].compositor) =
|
||||
ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
|
||||
event_state_compositors[i].compositor = ao2_container_alloc_hash(
|
||||
AO2_ALLOC_OPT_LOCK_MUTEX, 0, ESC_MAX_BUCKETS, esc_hash_fn, NULL, esc_cmp_fn);
|
||||
if (!event_state_compositors[i].compositor) {
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
@ -2617,7 +2618,8 @@ static int sip_tcptls_write(struct ast_tcptls_session_instance *tcptls_session,
|
|||
|
||||
ao2_lock(tcptls_session);
|
||||
|
||||
if (!(th = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")) ||
|
||||
if (!tcptls_session->stream ||
|
||||
!(th = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")) ||
|
||||
!(packet = ao2_alloc(sizeof(*packet), tcptls_packet_destructor)) ||
|
||||
!(packet->data = ast_str_create(len))) {
|
||||
goto tcptls_write_setup_error;
|
||||
|
@ -3139,7 +3141,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
|
|||
|
||||
if (read(me->alert_pipe[0], &alert, sizeof(alert)) == -1) {
|
||||
ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
|
||||
continue;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
switch (alert) {
|
||||
|
@ -3157,10 +3159,13 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
|
|||
ast_log(LOG_WARNING, "Failure to write to tcp/tls socket\n");
|
||||
}
|
||||
ao2_t_ref(packet, -1, "tcptls packet sent, this is no longer needed");
|
||||
} else {
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown tcptls thread alert '%u'\n", alert);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5312,6 +5317,7 @@ static void sip_destroy_peer(struct sip_peer *peer)
|
|||
|
||||
register_peer_exten(peer, FALSE);
|
||||
ast_free_acl_list(peer->acl);
|
||||
ast_free_acl_list(peer->contactacl);
|
||||
ast_free_acl_list(peer->directmediaacl);
|
||||
if (peer->selfdestruct)
|
||||
ast_atomic_fetchadd_int(&apeerobjs, -1);
|
||||
|
@ -10959,7 +10965,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
|
|||
ast_rtp_lookup_mime_multiple2(s3, NULL, newnoncodeccapability, 0, 0));
|
||||
}
|
||||
|
||||
if (portno != -1 || vportno != -1 || tportno != -1) {
|
||||
/* When UDPTL is negotiated it is expected that there are no compatible codecs as audio or
|
||||
* video is not being transported, thus we continue in this function further up if that is
|
||||
* the case. If we receive an SDP answer containing both a UDPTL stream and another media
|
||||
* stream however we need to check again to ensure that there is at least one joint codec
|
||||
* instead of assuming there is one.
|
||||
*/
|
||||
if ((portno != -1 || vportno != -1 || tportno != -1) && ast_format_cap_count(newjointcapability)) {
|
||||
/* We are now ready to change the sip session and RTP structures with the offered codecs, since
|
||||
they are acceptable */
|
||||
unsigned int framing;
|
||||
|
@ -11631,15 +11643,16 @@ static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_c
|
|||
ast_verbose("Discarded description format %s for ID %u\n", mimeSubtype, codec);
|
||||
}
|
||||
} else if (!strncmp(a, red_fmtp, strlen(red_fmtp))) {
|
||||
char *rest = NULL;
|
||||
/* count numbers of generations in fmtp */
|
||||
red_cp = &red_fmtp[strlen(red_fmtp)];
|
||||
strncpy(red_fmtp, a, 100);
|
||||
|
||||
sscanf(red_cp, "%30u", (unsigned *)&red_data_pt[*red_num_gen]);
|
||||
red_cp = strtok(red_cp, "/");
|
||||
red_cp = strtok_r(red_cp, "/", &rest);
|
||||
while (red_cp && (*red_num_gen)++ < AST_RED_MAX_GENERATION) {
|
||||
sscanf(red_cp, "%30u", (unsigned *)&red_data_pt[*red_num_gen]);
|
||||
red_cp = strtok(NULL, "/");
|
||||
red_cp = strtok_r(NULL, "/", &rest);
|
||||
}
|
||||
red_cp = red_fmtp;
|
||||
found = TRUE;
|
||||
|
@ -15635,7 +15648,7 @@ static int manager_sipnotify(struct mansession *s, const struct message *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (create_addr(p, channame, NULL, 0)) {
|
||||
if (create_addr(p, channame, NULL, 1)) {
|
||||
/* Maybe they're not registered, etc. */
|
||||
dialog_unlink_all(p);
|
||||
dialog_unref(p, "unref dialog inside for loop" );
|
||||
|
@ -17490,6 +17503,8 @@ static void network_change_stasis_subscribe(void)
|
|||
if (!network_change_sub) {
|
||||
network_change_sub = stasis_subscribe(ast_system_topic(),
|
||||
network_change_stasis_cb, NULL);
|
||||
stasis_subscription_accept_message_type(network_change_sub, ast_network_change_type());
|
||||
stasis_subscription_set_filter(network_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17503,6 +17518,8 @@ static void acl_change_stasis_subscribe(void)
|
|||
if (!acl_change_sub) {
|
||||
acl_change_sub = stasis_subscribe(ast_security_topic(),
|
||||
acl_change_stasis_cb, NULL);
|
||||
stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
|
||||
stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19228,18 +19245,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
bogus_peer = NULL;
|
||||
}
|
||||
|
||||
/* build_peer, called through sip_find_peer, is not able to check the
|
||||
* sip_pvt->natdetected flag in order to determine if the peer is behind
|
||||
* NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA
|
||||
* are set on the peer. So we check for that here and set the peer's
|
||||
* address accordingly.
|
||||
*/
|
||||
set_peer_nat(p, peer);
|
||||
|
||||
if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_sockaddr_copy(&peer->addr, &p->recv);
|
||||
}
|
||||
|
||||
if (!ast_apply_acl(peer->acl, addr, "SIP Peer ACL: ")) {
|
||||
ast_debug(2, "Found peer '%s' for '%s', but fails host access\n", peer->name, of);
|
||||
sip_unref_peer(peer, "sip_unref_peer: check_peer_ok: from sip_find_peer call, early return of AUTH_ACL_FAILED");
|
||||
|
@ -19308,6 +19313,21 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
ast_string_field_set(p, peermd5secret, NULL);
|
||||
}
|
||||
if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable))) {
|
||||
|
||||
/* build_peer, called through sip_find_peer, is not able to check the
|
||||
* sip_pvt->natdetected flag in order to determine if the peer is behind
|
||||
* NAT or not when SIP_PAGE3_NAT_AUTO_RPORT or SIP_PAGE3_NAT_AUTO_COMEDIA
|
||||
* are set on the peer. So we check for that here and set the peer's
|
||||
* address accordingly. The address should ONLY be set once we are sure
|
||||
* authentication was a success. If, for example, an INVITE was sent that
|
||||
* matched the peer name but failed the authentication check, the address
|
||||
* would be updated, which is bad.
|
||||
*/
|
||||
set_peer_nat(p, peer);
|
||||
if (p->natdetected && ast_test_flag(&peer->flags[2], SIP_PAGE3_NAT_AUTO_RPORT)) {
|
||||
ast_sockaddr_copy(&peer->addr, &p->recv);
|
||||
}
|
||||
|
||||
/* If we have a call limit, set flag */
|
||||
if (peer->call_limit)
|
||||
ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
|
||||
|
@ -19407,6 +19427,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
|
|||
}
|
||||
}
|
||||
sip_unref_peer(peer, "check_peer_ok: sip_unref_peer: tossing temp ptr to peer from sip_find_peer");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -21169,6 +21190,7 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct
|
|||
ast_cli(fd, " Force rport : %s\n", force_rport_string(peer->flags));
|
||||
ast_cli(fd, " Symmetric RTP: %s\n", comedia_string(peer->flags));
|
||||
ast_cli(fd, " ACL : %s\n", AST_CLI_YESNO(ast_acl_list_is_empty(peer->acl) == 0));
|
||||
ast_cli(fd, " ContactACL : %s\n", AST_CLI_YESNO(ast_acl_list_is_empty(peer->contactacl) == 0));
|
||||
ast_cli(fd, " DirectMedACL : %s\n", AST_CLI_YESNO(ast_acl_list_is_empty(peer->directmediaacl) == 0));
|
||||
ast_cli(fd, " T.38 support : %s\n", AST_CLI_YESNO(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
|
||||
ast_cli(fd, " T.38 EC mode : %s\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)));
|
||||
|
@ -25899,7 +25921,13 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req,
|
|||
}
|
||||
ao2_ref(bridge, -1);
|
||||
} else {
|
||||
ast_channel_move(replaces_chan, c);
|
||||
int pickedup;
|
||||
ast_channel_lock(replaces_chan);
|
||||
pickedup = ast_can_pickup(replaces_chan) && !ast_do_pickup(c, replaces_chan);
|
||||
ast_channel_unlock(replaces_chan);
|
||||
if (!pickedup) {
|
||||
ast_channel_move(replaces_chan, c);
|
||||
}
|
||||
ast_hangup(c);
|
||||
}
|
||||
ast_channel_unref(c);
|
||||
|
@ -28375,6 +28403,9 @@ static void add_peer_mwi_subs(struct sip_peer *peer)
|
|||
mailbox_specific_topic = ast_mwi_topic(mailbox->id);
|
||||
if (mailbox_specific_topic) {
|
||||
mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer);
|
||||
stasis_subscription_accept_message_type(mailbox->event_sub, ast_mwi_state_type());
|
||||
stasis_subscription_accept_message_type(mailbox->event_sub, stasis_subscription_change_type());
|
||||
stasis_subscription_set_filter(mailbox->event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31506,6 +31537,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head
|
|||
struct ast_variable *v = v_head;
|
||||
struct sip_peer *peer = NULL;
|
||||
struct ast_acl_list *oldacl = NULL;
|
||||
struct ast_acl_list *oldcontactacl = NULL;
|
||||
struct ast_acl_list *olddirectmediaacl = NULL;
|
||||
int found = 0;
|
||||
int firstpass = 1;
|
||||
|
@ -31583,6 +31615,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head
|
|||
if (firstpass) {
|
||||
oldacl = peer->acl;
|
||||
peer->acl = NULL;
|
||||
oldcontactacl = peer->contactacl;
|
||||
peer->contactacl = NULL;
|
||||
olddirectmediaacl = peer->directmediaacl;
|
||||
peer->directmediaacl = NULL;
|
||||
set_peer_defaults(peer); /* Set peer defaults */
|
||||
|
@ -32265,6 +32299,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head
|
|||
peer->the_mark = 0;
|
||||
|
||||
oldacl = ast_free_acl_list(oldacl);
|
||||
oldcontactacl = ast_free_acl_list(oldcontactacl);
|
||||
olddirectmediaacl = ast_free_acl_list(olddirectmediaacl);
|
||||
if (!ast_strlen_zero(peer->callback)) { /* build string from peer info */
|
||||
char *reg_string;
|
||||
|
@ -33157,7 +33192,8 @@ static int reload_config(enum channelreloadreason reason)
|
|||
ast_log(LOG_WARNING, "Usage of SIP_CAUSE is deprecated. Please use HANGUPCAUSE instead.\n");
|
||||
}
|
||||
} else if (!strcasecmp(v->name, "qualifygap")) {
|
||||
if (sscanf(v->value, "%30d", &global_qualify_gap) != 1) {
|
||||
if (sscanf(v->value, "%30d", &global_qualify_gap) != 1
|
||||
|| global_qualify_gap < 0) {
|
||||
ast_log(LOG_WARNING, "Invalid qualifygap '%s' at line %d of %s\n", v->value, v->lineno, config);
|
||||
global_qualify_gap = DEFAULT_QUALIFY_GAP;
|
||||
}
|
||||
|
@ -34399,17 +34435,14 @@ static int peer_iphash_cb(const void *obj, const int flags)
|
|||
* This function has two modes.
|
||||
* - If the peer arg does not have INSECURE_PORT set, then we will only return
|
||||
* a match for a peer that matches both the IP and port.
|
||||
* - If the peer arg does have the INSECURE_PORT flag set, then we will only
|
||||
* return a match for a peer that matches the IP and has insecure=port
|
||||
* in its configuration.
|
||||
* - If the peer arg does have the INSECURE_PORT flag set, then we will return
|
||||
* a match for UDP peers with insecure=port set, or a peer that does NOT have
|
||||
* host=dynamic for other protocols (or have a valid Contact: header in REGISTER).
|
||||
* This callback will be used twice when doing peer matching, as per the two modes
|
||||
* described above.
|
||||
*
|
||||
* This callback will be used twice when doing peer matching. There is a first
|
||||
* pass for full IP+port matching, and a second pass in case there is a match
|
||||
* that meets the insecure=port criteria.
|
||||
*
|
||||
* \note Connections coming in over TCP or TLS should never be matched by port.
|
||||
*
|
||||
* \note the peer's addr struct provides to fields combined to make a key: the sin_addr.s_addr and sin_port fields.
|
||||
* \note the peer's addr struct provides to fields combined to make a key: the
|
||||
* sin_addr.s_addr and sin_port fields (transport is compared separately).
|
||||
*/
|
||||
static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
|
@ -34428,24 +34461,50 @@ static int peer_ipcmp_cb_full(void *obj, void *arg, void *data, int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* We matched the IP, check to see if we need to match by port as well. */
|
||||
if (((peer->transports & peer2->transports) &
|
||||
(AST_TRANSPORT_UDP | AST_TRANSPORT_WS | AST_TRANSPORT_WSS)) &&
|
||||
ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
|
||||
if ((peer->transports & peer2->transports) == 0) {
|
||||
/* transport setting doesn't match */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
|
||||
/* On the first pass only match if ports match. */
|
||||
return ast_sockaddr_port(&peer->addr) == ast_sockaddr_port(&peer2->addr) ?
|
||||
(CMP_MATCH | CMP_STOP) : 0;
|
||||
}
|
||||
|
||||
/* We can reach here only if peer2 is for SIP_INSECURE_PORT, in
|
||||
* other words, the second pass where we only try to match against IP.
|
||||
*
|
||||
* Some special handling for UDP vs non-UDP (TCP, TLS, WS and WSS), since
|
||||
* for non-UDP the source port won't typically be controlled, we only want
|
||||
* to check the source IP, but only if the host isn't dynamic. This isn't
|
||||
* done in the first pass so that if a peer registers from the same IP as
|
||||
* a static IP peer that registration (port match) will take prescedence).
|
||||
*/
|
||||
if (peer2->transports == AST_TRANSPORT_UDP) {
|
||||
/* We are allowing match without port for peers configured that
|
||||
* way in this pass through the peers. */
|
||||
return ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) ?
|
||||
(CMP_MATCH | CMP_STOP) : 0;
|
||||
}
|
||||
|
||||
/* Now only return a match if the port matches, as well. */
|
||||
return ast_sockaddr_port(&peer->addr) == ast_sockaddr_port(&peer2->addr) ?
|
||||
(CMP_MATCH | CMP_STOP) : 0;
|
||||
}
|
||||
if (!peer->host_dynamic) {
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
|
||||
static int peer_ipcmp_cb(void *obj, void *arg, int flags)
|
||||
{
|
||||
return peer_ipcmp_cb_full(obj, arg, NULL, flags);
|
||||
/* Conditions taken from parse_register_contact() */
|
||||
if (peer2->transports & (AST_TRANSPORT_WS | AST_TRANSPORT_WSS)) {
|
||||
/* The contact address of websockets is always the transport source address and port */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT)) {
|
||||
/* The contact address of NATed peers is always the transport source address and port */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Have to assume that we used the registered contact header (non-NAT) */
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
|
||||
static int threadt_hash_cb(const void *obj, const int flags)
|
||||
|
@ -35333,12 +35392,18 @@ static int load_module(void)
|
|||
|
||||
/* the fact that ao2_containers can't resize automatically is a major worry! */
|
||||
/* if the number of objects gets above MAX_XXX_BUCKETS, things will slow down */
|
||||
peers = ao2_t_container_alloc(HASH_PEER_SIZE, peer_hash_cb, peer_cmp_cb, "allocate peers");
|
||||
peers_by_ip = ao2_t_container_alloc(HASH_PEER_SIZE, peer_iphash_cb, peer_ipcmp_cb, "allocate peers_by_ip");
|
||||
dialogs = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs");
|
||||
dialogs_needdestroy = ao2_t_container_alloc(1, NULL, NULL, "allocate dialogs_needdestroy");
|
||||
dialogs_rtpcheck = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs for rtpchecks");
|
||||
threadt = ao2_t_container_alloc(HASH_DIALOG_SIZE, threadt_hash_cb, threadt_cmp_cb, "allocate threadt table");
|
||||
peers = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_PEER_SIZE,
|
||||
peer_hash_cb, NULL, peer_cmp_cb, "allocate peers");
|
||||
peers_by_ip = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_PEER_SIZE,
|
||||
peer_iphash_cb, NULL, NULL, "allocate peers_by_ip");
|
||||
dialogs = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_DIALOG_SIZE,
|
||||
dialog_hash_cb, NULL, dialog_cmp_cb, "allocate dialogs");
|
||||
dialogs_needdestroy = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 1,
|
||||
NULL, NULL, NULL, "allocate dialogs_needdestroy");
|
||||
dialogs_rtpcheck = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_DIALOG_SIZE,
|
||||
dialog_hash_cb, NULL, dialog_cmp_cb, "allocate dialogs for rtpchecks");
|
||||
threadt = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_DIALOG_SIZE,
|
||||
threadt_hash_cb, NULL, threadt_cmp_cb, "allocate threadt table");
|
||||
if (!peers || !peers_by_ip || !dialogs || !dialogs_needdestroy || !dialogs_rtpcheck
|
||||
|| !threadt) {
|
||||
ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n");
|
||||
|
@ -35352,7 +35417,8 @@ static int load_module(void)
|
|||
}
|
||||
ast_format_cap_append_by_type(sip_tech.capabilities, AST_MEDIA_TYPE_AUDIO);
|
||||
|
||||
registry_list = ao2_t_container_alloc(HASH_REGISTRY_SIZE, registry_hash_cb, registry_cmp_cb, "allocate registry_list");
|
||||
registry_list = ao2_t_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, HASH_REGISTRY_SIZE,
|
||||
registry_hash_cb, NULL, registry_cmp_cb, "allocate registry_list");
|
||||
subscription_mwi_list = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
|
||||
AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN, NULL, NULL, "allocate subscription_mwi_list");
|
||||
|
||||
|
@ -35470,7 +35536,9 @@ static int load_module(void)
|
|||
unload_module();
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
if (!(sip_monitor_instances = ao2_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn))) {
|
||||
sip_monitor_instances = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
|
||||
sip_monitor_instance_hash_fn, NULL, sip_monitor_instance_cmp_fn);
|
||||
if (!sip_monitor_instances) {
|
||||
unload_module();
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
@ -35717,7 +35785,7 @@ static int unload_module(void)
|
|||
}
|
||||
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Session Initiation Protocol (SIP)",
|
||||
.support_level = AST_MODULE_SUPPORT_CORE,
|
||||
.support_level = AST_MODULE_SUPPORT_EXTENDED,
|
||||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.reload = reload,
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "asterisk/causes.h"
|
||||
#include "asterisk/pickup.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/dsp.h"
|
||||
|
@ -8334,6 +8335,8 @@ static struct skinny_line *config_line(const char *lname, struct ast_variable *v
|
|||
mailbox_specific_topic = ast_mwi_topic(l->mailbox);
|
||||
if (mailbox_specific_topic) {
|
||||
l->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, l);
|
||||
stasis_subscription_accept_message_type(l->mwi_event_sub, ast_mwi_state_type());
|
||||
stasis_subscription_set_filter(l->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,11 +62,13 @@
|
|||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/rtp_engine.h"
|
||||
#include "asterisk/unaligned.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
#include "asterisk/acl.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/indications.h"
|
||||
|
@ -574,7 +576,7 @@ static const unsigned char packet_send_stream_based_tone_on[] =
|
|||
{ 0x16, 0x06, 0x1b, 0x00, 0x00, 0x05 };
|
||||
static const unsigned char packet_send_stream_based_tone_single_freq[] =
|
||||
{ 0x16, 0x06, 0x1d, 0x00, 0x01, 0xb8 };
|
||||
static const unsigned char packet_send_stream_based_tone_dial_freq[] =
|
||||
static const unsigned char packet_send_stream_based_tone_dual_freq[] =
|
||||
{ 0x16, 0x08, 0x1d, 0x00, 0x01, 0xb8, 0x01, 0x5e };
|
||||
static const unsigned char packet_send_select_output[] =
|
||||
{ 0x16, 0x06, 0x32, 0xc0, 0x01, 0x00 };
|
||||
|
@ -813,7 +815,9 @@ static const char *ustmtext(const char *str, struct unistimsession *pte)
|
|||
char tmp[1024], *p, *p_orig = NULL, *p_trans = NULL;
|
||||
FILE *f;
|
||||
|
||||
if (!(lang->trans = ao2_container_alloc(8, lang_hash_fn, lang_cmp_fn))) {
|
||||
lang->trans = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 8,
|
||||
lang_hash_fn, NULL, lang_cmp_fn);
|
||||
if (!lang->trans) {
|
||||
ast_log(LOG_ERROR, "Unable to allocate container for translation!\n");
|
||||
return str;
|
||||
}
|
||||
|
@ -999,27 +1003,36 @@ static int get_to_address(int fd, struct sockaddr_in *toAddr)
|
|||
{
|
||||
#ifdef HAVE_PKTINFO
|
||||
int err;
|
||||
struct msghdr msg;
|
||||
struct {
|
||||
struct cmsghdr cm;
|
||||
int len;
|
||||
struct in_addr address;
|
||||
} ip_msg;
|
||||
|
||||
/* Zero out the structures before we use them */
|
||||
/* This sets several key values to NULL */
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&ip_msg, 0, sizeof(ip_msg));
|
||||
|
||||
/* Initialize the message structure */
|
||||
msg.msg_control = &ip_msg;
|
||||
msg.msg_controllen = sizeof(ip_msg);
|
||||
char cmbuf[0x100];
|
||||
struct cmsghdr *cmsg;
|
||||
struct sockaddr_in peeraddr;
|
||||
struct in_addr addr;
|
||||
struct msghdr mh = {
|
||||
.msg_name = &peeraddr,
|
||||
.msg_namelen = sizeof(peeraddr),
|
||||
.msg_control = cmbuf,
|
||||
.msg_controllen = sizeof(cmbuf),
|
||||
};
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
/* Get info about the incoming packet */
|
||||
err = recvmsg(fd, &msg, MSG_PEEK);
|
||||
err = recvmsg(fd, &mh, MSG_PEEK);
|
||||
if (err == -1) {
|
||||
ast_log(LOG_WARNING, "recvmsg returned an error: %s\n", strerror(errno));
|
||||
return err;
|
||||
}
|
||||
memcpy(&toAddr->sin_addr, &ip_msg.address, sizeof(struct in_addr));
|
||||
for(cmsg = CMSG_FIRSTHDR(&mh);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&mh, cmsg))
|
||||
{
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
||||
struct in_pktinfo *pkt = (struct in_pktinfo*)CMSG_DATA(cmsg);
|
||||
addr = pkt->ipi_addr;
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "message received on address %s\n", ast_inet_ntoa(addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(&toAddr->sin_addr, &addr, sizeof(struct in_addr));
|
||||
return err;
|
||||
#else
|
||||
memcpy(toAddr, &public_ip, sizeof(*toAddr));
|
||||
|
@ -1027,6 +1040,7 @@ static int get_to_address(int fd, struct sockaddr_in *toAddr)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Allocate memory & initialize structures for a new phone */
|
||||
/* addr_from : ip address of the phone */
|
||||
static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
|
||||
|
@ -1038,7 +1052,10 @@ static struct unistimsession *create_client(const struct sockaddr_in *addr_from)
|
|||
return NULL;
|
||||
|
||||
memcpy(&s->sin, addr_from, sizeof(struct sockaddr_in));
|
||||
get_to_address(unistimsock, &s->sout);
|
||||
if (get_to_address(unistimsock, &s->sout) < 0) {
|
||||
ast_free(s);
|
||||
return NULL;
|
||||
}
|
||||
s->sout.sin_family = AF_INET;
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "Creating a new entry for the phone from %s received via server ip %s\n",
|
||||
|
@ -1205,19 +1222,16 @@ static void send_tone(struct unistimsession *pte, uint16_t tone1, uint16_t tone2
|
|||
if (!tone2) {
|
||||
memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_single_freq,
|
||||
sizeof(packet_send_stream_based_tone_single_freq));
|
||||
buffsend[10] = (tone1 & 0xff00) >> 8;
|
||||
buffsend[11] = (tone1 & 0x00ff);
|
||||
put_unaligned_uint16(&buffsend[10], htons(tone1));
|
||||
send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_single_freq), buffsend,
|
||||
pte);
|
||||
} else {
|
||||
tone2 *= 8;
|
||||
memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dial_freq,
|
||||
sizeof(packet_send_stream_based_tone_dial_freq));
|
||||
buffsend[10] = (tone1 & 0xff00) >> 8;
|
||||
buffsend[11] = (tone1 & 0x00ff);
|
||||
buffsend[12] = (tone2 & 0xff00) >> 8;
|
||||
buffsend[13] = (tone2 & 0x00ff);
|
||||
send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dial_freq), buffsend,
|
||||
memcpy(buffsend + SIZE_HEADER, packet_send_stream_based_tone_dual_freq,
|
||||
sizeof(packet_send_stream_based_tone_dual_freq));
|
||||
put_unaligned_uint16(&buffsend[10], htons(tone1));
|
||||
put_unaligned_uint16(&buffsend[12], htons(tone2));
|
||||
send_client(SIZE_HEADER + sizeof(packet_send_stream_based_tone_dual_freq), buffsend,
|
||||
pte);
|
||||
}
|
||||
|
||||
|
@ -2744,7 +2758,7 @@ static void send_start_rtp(struct unistim_subchannel *sub)
|
|||
sizeof(packet_send_jitter_buffer_conf));
|
||||
send_client(SIZE_HEADER + sizeof(packet_send_jitter_buffer_conf), buffsend, pte);
|
||||
if (pte->device->rtp_method != 0) {
|
||||
uint16_t rtcpsin_port = htons(us.sin_port) + 1; /* RTCP port is RTP + 1 */
|
||||
uint16_t rtcpsin_port = ntohs(us.sin_port) + 1; /* RTCP port is RTP + 1 */
|
||||
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "Sending OpenAudioStreamTX using method #%d\n", pte->device->rtp_method);
|
||||
|
@ -2758,20 +2772,14 @@ static void send_start_rtp(struct unistim_subchannel *sub)
|
|||
}
|
||||
if (pte->device->rtp_method != 2) {
|
||||
memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
|
||||
buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
|
||||
buffsend[21] = (htons(sin.sin_port) & 0x00ff);
|
||||
buffsend[23] = (rtcpsin_port & 0x00ff);
|
||||
buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
|
||||
buffsend[25] = (us.sin_port & 0xff00) >> 8;
|
||||
buffsend[24] = (us.sin_port & 0x00ff);
|
||||
buffsend[27] = (rtcpsin_port & 0x00ff);
|
||||
buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
|
||||
put_unaligned_uint16(&buffsend[20], sin.sin_port);
|
||||
put_unaligned_uint16(&buffsend[22], htons(rtcpsin_port));
|
||||
put_unaligned_uint16(&buffsend[24], us.sin_port);
|
||||
put_unaligned_uint16(&buffsend[26], htons(rtcpsin_port));
|
||||
} else {
|
||||
memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
|
||||
buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
|
||||
buffsend[16] = (htons(sin.sin_port) & 0x00ff);
|
||||
buffsend[20] = (us.sin_port & 0xff00) >> 8;
|
||||
buffsend[19] = (us.sin_port & 0x00ff);
|
||||
put_unaligned_uint16(&buffsend[15], sin.sin_port);
|
||||
put_unaligned_uint16(&buffsend[19], us.sin_port);
|
||||
}
|
||||
buffsend[11] = codec; /* rx */
|
||||
buffsend[12] = codec; /* tx */
|
||||
|
@ -2789,20 +2797,14 @@ static void send_start_rtp(struct unistim_subchannel *sub)
|
|||
}
|
||||
if (pte->device->rtp_method != 2) {
|
||||
memcpy(buffsend + 28, &public.sin_addr, sizeof(public.sin_addr));
|
||||
buffsend[20] = (htons(sin.sin_port) & 0xff00) >> 8;
|
||||
buffsend[21] = (htons(sin.sin_port) & 0x00ff);
|
||||
buffsend[23] = (rtcpsin_port & 0x00ff);
|
||||
buffsend[22] = (rtcpsin_port & 0xff00) >> 8;
|
||||
buffsend[25] = (us.sin_port & 0xff00) >> 8;
|
||||
buffsend[24] = (us.sin_port & 0x00ff);
|
||||
buffsend[27] = (rtcpsin_port & 0x00ff);
|
||||
buffsend[26] = (rtcpsin_port & 0xff00) >> 8;
|
||||
put_unaligned_uint16(&buffsend[20], sin.sin_port);
|
||||
put_unaligned_uint16(&buffsend[22], htons(rtcpsin_port));
|
||||
put_unaligned_uint16(&buffsend[24], us.sin_port);
|
||||
put_unaligned_uint16(&buffsend[26], htons(rtcpsin_port));
|
||||
} else {
|
||||
memcpy(buffsend + 23, &public.sin_addr, sizeof(public.sin_addr));
|
||||
buffsend[15] = (htons(sin.sin_port) & 0xff00) >> 8;
|
||||
buffsend[16] = (htons(sin.sin_port) & 0x00ff);
|
||||
buffsend[20] = (us.sin_port & 0xff00) >> 8;
|
||||
buffsend[19] = (us.sin_port & 0x00ff);
|
||||
put_unaligned_uint16(&buffsend[15], sin.sin_port);
|
||||
put_unaligned_uint16(&buffsend[19], us.sin_port);
|
||||
}
|
||||
buffsend[11] = codec; /* rx */
|
||||
buffsend[12] = codec; /* tx */
|
||||
|
@ -2817,11 +2819,9 @@ static void send_start_rtp(struct unistim_subchannel *sub)
|
|||
memcpy(buffsend + SIZE_HEADER, packet_send_call, sizeof(packet_send_call));
|
||||
memcpy(buffsend + 53, &public.sin_addr, sizeof(public.sin_addr));
|
||||
/* Destination port when sending RTP */
|
||||
buffsend[49] = (us.sin_port & 0x00ff);
|
||||
buffsend[50] = (us.sin_port & 0xff00) >> 8;
|
||||
put_unaligned_uint16(&buffsend[49], us.sin_port);
|
||||
/* Destination port when sending RTCP */
|
||||
buffsend[52] = (rtcpsin_port & 0x00ff);
|
||||
buffsend[51] = (rtcpsin_port & 0xff00) >> 8;
|
||||
put_unaligned_uint16(&buffsend[51], htons(rtcpsin_port));
|
||||
/* Codec */
|
||||
buffsend[40] = codec;
|
||||
buffsend[41] = codec;
|
||||
|
@ -2838,10 +2838,8 @@ static void send_start_rtp(struct unistim_subchannel *sub)
|
|||
ast_format_get_name(ast_channel_readformat(sub->owner)));
|
||||
}
|
||||
/* Source port for transmit RTP and Destination port for receiving RTP */
|
||||
buffsend[45] = (htons(sin.sin_port) & 0xff00) >> 8;
|
||||
buffsend[46] = (htons(sin.sin_port) & 0x00ff);
|
||||
buffsend[47] = (rtcpsin_port & 0xff00) >> 8;
|
||||
buffsend[48] = (rtcpsin_port & 0x00ff);
|
||||
put_unaligned_uint16(&buffsend[45], sin.sin_port);
|
||||
put_unaligned_uint16(&buffsend[47], htons(rtcpsin_port));
|
||||
send_client(SIZE_HEADER + sizeof(packet_send_call), buffsend, pte);
|
||||
}
|
||||
}
|
||||
|
@ -3328,22 +3326,12 @@ static void handle_call_incoming(struct unistimsession *s)
|
|||
return;
|
||||
}
|
||||
|
||||
static int unistim_do_senddigit(struct unistimsession *pte, char digit)
|
||||
static int send_dtmf_tone(struct unistimsession *pte, char digit)
|
||||
{
|
||||
struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
|
||||
struct unistim_subchannel *sub;
|
||||
int row, col;
|
||||
int row, col;
|
||||
|
||||
sub = get_sub(pte->device, SUB_REAL);
|
||||
if (!sub || !sub->owner || sub->alreadygone) {
|
||||
ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send DTMF indication _before_ playing sounds */
|
||||
ast_queue_frame(sub->owner, &f);
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "Send Digit %c (%i ms)\n", digit, pte->device->dtmfduration);
|
||||
ast_verb(0, "Phone Play Digit %c\n", digit);
|
||||
}
|
||||
if (pte->device->dtmfduration > 0) {
|
||||
row = (digit - '1') % 3;
|
||||
|
@ -3361,6 +3349,28 @@ static int unistim_do_senddigit(struct unistimsession *pte, char digit)
|
|||
} else {
|
||||
send_tone(pte, 500, 2000);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unistim_do_senddigit(struct unistimsession *pte, char digit)
|
||||
{
|
||||
struct ast_frame f = { .frametype = AST_FRAME_DTMF, .subclass.integer = digit, .src = "unistim" };
|
||||
struct unistim_subchannel *sub;
|
||||
|
||||
sub = get_sub(pte->device, SUB_REAL);
|
||||
if (!sub || !sub->owner || sub->alreadygone) {
|
||||
ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send DTMF indication _before_ playing sounds */
|
||||
ast_queue_frame(sub->owner, &f);
|
||||
if (pte->device->dtmfduration > 0) {
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "Send Digit %c (%i ms)\n", digit, pte->device->dtmfduration);
|
||||
}
|
||||
send_dtmf_tone(pte, digit);
|
||||
usleep(pte->device->dtmfduration * 1000); /* XXX Less than perfect, blocking an important thread is not a good idea */
|
||||
send_tone(pte, 0, 0);
|
||||
}
|
||||
|
@ -5503,34 +5513,21 @@ static int unistim_senddigit_begin(struct ast_channel *ast, char digit)
|
|||
if (!pte) {
|
||||
return -1;
|
||||
}
|
||||
return unistim_do_senddigit(pte, digit);
|
||||
return send_dtmf_tone(pte, digit);
|
||||
}
|
||||
|
||||
static int unistim_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
|
||||
{
|
||||
struct unistimsession *pte = channel_to_session(ast);
|
||||
struct ast_frame f = { 0, };
|
||||
struct unistim_subchannel *sub;
|
||||
|
||||
sub = get_sub(pte->device, SUB_REAL);
|
||||
|
||||
if (!sub || !sub->owner || sub->alreadygone) {
|
||||
ast_log(LOG_WARNING, "Unable to find subchannel in dtmf senddigit_end\n");
|
||||
if (!pte) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unistimdebug) {
|
||||
ast_verb(0, "Send Digit off %c\n", digit);
|
||||
}
|
||||
if (!pte) {
|
||||
return -1;
|
||||
ast_verb(0, "Send Digit off %c (duration %d)\n", digit, duration);
|
||||
}
|
||||
send_tone(pte, 0, 0);
|
||||
f.frametype = AST_FRAME_DTMF;
|
||||
f.subclass.integer = digit;
|
||||
f.src = "unistim";
|
||||
ast_queue_frame(sub->owner, &f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
|
|||
|
||||
if (!channel) {
|
||||
ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_lock(channel);
|
||||
|
@ -364,7 +364,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
|
|||
ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
|
||||
ast_channel_unlock(channel);
|
||||
ao2_cleanup(channel);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
|
||||
|
@ -372,7 +372,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
|
|||
ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
|
||||
ast_channel_unlock(channel);
|
||||
ao2_cleanup(channel);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtp = ao2_bump(media->rtp);
|
||||
|
|
|
@ -121,6 +121,60 @@
|
|||
<ref type="function">PJSIP_MEDIA_OFFER</ref>
|
||||
</see-also>
|
||||
</function>
|
||||
<function name="PJSIP_PARSE_URI" language="en_US">
|
||||
<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">
|
||||
|
@ -529,7 +583,13 @@ static int channel_read_rtp(struct ast_channel *chan, const char *type, const ch
|
|||
} else if (!strcmp(type, "direct")) {
|
||||
ast_copy_string(buf, ast_sockaddr_stringify(&media->direct_media_addr), buflen);
|
||||
} else if (!strcmp(type, "secure")) {
|
||||
snprintf(buf, buflen, "%d", media->srtp ? 1 : 0);
|
||||
if (media->srtp) {
|
||||
struct ast_sdp_srtp *srtp = media->srtp;
|
||||
int flag = ast_test_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK);
|
||||
snprintf(buf, buflen, "%d", flag ? 1 : 0);
|
||||
} else {
|
||||
snprintf(buf, buflen, "%d", 0);
|
||||
}
|
||||
} else if (!strcmp(type, "hold")) {
|
||||
snprintf(buf, buflen, "%d", media->remotely_held ? 1 : 0);
|
||||
} else {
|
||||
|
@ -1035,6 +1095,127 @@ static struct session_refresh_state *session_refresh_state_get_or_alloc(struct a
|
|||
return state;
|
||||
}
|
||||
|
||||
/*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */
|
||||
struct parse_uri_args {
|
||||
const char *uri;
|
||||
const char *type;
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
int ret;
|
||||
};
|
||||
|
||||
/*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */
|
||||
static int parse_uri_cb(void *data)
|
||||
{
|
||||
struct parse_uri_args *args = data;
|
||||
pj_pool_t *pool;
|
||||
pjsip_name_addr *uri;
|
||||
pjsip_sip_uri *sip_uri;
|
||||
pj_str_t tmp;
|
||||
|
||||
args->ret = 0;
|
||||
|
||||
pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128);
|
||||
if (!pool) {
|
||||
ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n");
|
||||
args->ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pj_strdup2_with_null(pool, &tmp, args->uri);
|
||||
uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
|
||||
if (!uri || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
|
||||
ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri);
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
args->ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(args->type, "scheme")) {
|
||||
ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen);
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
return 0;
|
||||
} else if (!strcmp(args->type, "display")) {
|
||||
ast_copy_pj_str(args->buf, &uri->display, args->buflen);
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sip_uri = pjsip_uri_get_uri(uri);
|
||||
if (!sip_uri) {
|
||||
ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri);
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
args->ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(args->type, "user")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen);
|
||||
} else if (!strcmp(args->type, "passwd")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen);
|
||||
} else if (!strcmp(args->type, "host")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen);
|
||||
} else if (!strcmp(args->type, "port")) {
|
||||
snprintf(args->buf, args->buflen, "%d", sip_uri->port);
|
||||
} else if (!strcmp(args->type, "user_param")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen);
|
||||
} else if (!strcmp(args->type, "method_param")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen);
|
||||
} else if (!strcmp(args->type, "transport_param")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen);
|
||||
} else if (!strcmp(args->type, "ttl_param")) {
|
||||
snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param);
|
||||
} else if (!strcmp(args->type, "lr_param")) {
|
||||
snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param);
|
||||
} else if (!strcmp(args->type, "maddr_param")) {
|
||||
ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen);
|
||||
} else {
|
||||
ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type);
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
args->ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
|
||||
{
|
||||
struct parse_uri_args func_args = { 0, };
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(uri_str);
|
||||
AST_APP_ARG(type);
|
||||
);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, data);
|
||||
|
||||
if (ast_strlen_zero(args.uri_str)) {
|
||||
ast_log(LOG_WARNING, "An URI must be specified when using the '%s' dialplan function\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.type)) {
|
||||
ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
|
||||
func_args.uri = args.uri_str;
|
||||
func_args.type = args.type;
|
||||
func_args.buf = buf;
|
||||
func_args.buflen = buflen;
|
||||
if (ast_sip_push_task_wait_serializer(NULL, parse_uri_cb, &func_args)) {
|
||||
ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return func_args.ret;
|
||||
}
|
||||
|
||||
static int media_offer_read_av(struct ast_sip_session *session, char *buf,
|
||||
size_t len, enum ast_media_type media_type)
|
||||
{
|
||||
|
|
|
@ -110,4 +110,17 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c
|
|||
*/
|
||||
int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
|
||||
|
||||
/*!
|
||||
* \brief PJSIP_PARSE_URI function read callback
|
||||
* \param chan The channel the function is called on
|
||||
* \param cmd The name of the function
|
||||
* \param data Arguments passed to the function
|
||||
* \param buf Out buffer that should be populated with the data
|
||||
* \param len Size of the buffer
|
||||
*
|
||||
* \retval 0 on success
|
||||
* \retval -1 on failure
|
||||
*/
|
||||
int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
|
||||
|
||||
#endif /* _PJSIP_DIALPLAN_FUNCTIONS */
|
|
@ -2968,11 +2968,16 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
|
|||
} else {
|
||||
c = p->dialdest;
|
||||
}
|
||||
|
||||
if (*c) {
|
||||
snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
|
||||
int numchars = snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
|
||||
if (numchars >= sizeof(p->dop.dialstr)) {
|
||||
ast_log(LOG_WARNING, "Dial string '%s' truncated\n", c);
|
||||
}
|
||||
} else {
|
||||
ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
|
||||
}
|
||||
|
||||
if (strlen(p->dop.dialstr) > 4) {
|
||||
memset(p->echorest, 'w', sizeof(p->echorest) - 1);
|
||||
strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
#include "asterisk/options.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/mwi.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/say.h"
|
||||
|
@ -1390,14 +1391,25 @@ static void pri_queue_control(struct sig_pri_span *pri, int chanpos, int subclas
|
|||
*/
|
||||
static void sig_pri_queue_hangup(struct sig_pri_span *pri, int chanpos)
|
||||
{
|
||||
struct ast_channel *owner;
|
||||
|
||||
if (sig_pri_callbacks.queue_control) {
|
||||
sig_pri_callbacks.queue_control(pri->pvts[chanpos]->chan_pvt, AST_CONTROL_HANGUP);
|
||||
}
|
||||
|
||||
sig_pri_lock_owner(pri, chanpos);
|
||||
if (pri->pvts[chanpos]->owner) {
|
||||
ast_queue_hangup(pri->pvts[chanpos]->owner);
|
||||
ast_channel_unlock(pri->pvts[chanpos]->owner);
|
||||
owner = pri->pvts[chanpos]->owner;
|
||||
if (owner) {
|
||||
ao2_ref(owner, +1);
|
||||
ast_queue_hangup(owner);
|
||||
ast_channel_unlock(owner);
|
||||
|
||||
/* Tell the CDR this DAHDI channel hung up */
|
||||
sig_pri_unlock_private(pri->pvts[chanpos]);
|
||||
ast_set_hangupsource(owner, ast_channel_name(owner), 0);
|
||||
sig_pri_lock_private(pri->pvts[chanpos]);
|
||||
|
||||
ao2_ref(owner, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6036,11 +6048,14 @@ static void sig_pri_handle_setup(struct sig_pri_span *pri, pri_event *e)
|
|||
|
||||
/* Setup the user tag for party id's from this device for this call. */
|
||||
if (pri->append_msn_to_user_tag) {
|
||||
snprintf(pri->pvts[chanpos]->user_tag,
|
||||
int len = snprintf(pri->pvts[chanpos]->user_tag,
|
||||
sizeof(pri->pvts[chanpos]->user_tag), "%s_%s",
|
||||
pri->initial_user_tag,
|
||||
pri->nodetype == PRI_NETWORK
|
||||
? plancallingnum : e->ring.callednum);
|
||||
if (len >= sizeof(pri->pvts[chanpos]->user_tag)) {
|
||||
ast_log(LOG_WARNING, "user_tag '%s' truncated\n", pri->pvts[chanpos]->user_tag);
|
||||
}
|
||||
} else {
|
||||
ast_copy_string(pri->pvts[chanpos]->user_tag,
|
||||
pri->initial_user_tag, sizeof(pri->pvts[chanpos]->user_tag));
|
||||
|
@ -6434,7 +6449,7 @@ static void *pri_dchannel(void *vpri)
|
|||
|
||||
if (e) {
|
||||
int chanpos = -1;
|
||||
char cause_str[35];
|
||||
char cause_str[36];
|
||||
|
||||
if (pri->debug) {
|
||||
ast_verbose("Span %d: Processing event %s(%d)\n",
|
||||
|
@ -9130,6 +9145,9 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
if (!pri->mbox[i].sub) {
|
||||
ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s(%s).\n",
|
||||
sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
|
||||
} else {
|
||||
stasis_subscription_accept_message_type(pri->mbox[i].sub, ast_mwi_state_type());
|
||||
stasis_subscription_set_filter(pri->mbox[i].sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
|
||||
}
|
||||
#if defined(HAVE_PRI_MWI_V2)
|
||||
if (ast_strlen_zero(pri->mbox[i].vm_number)) {
|
||||
|
@ -10130,8 +10148,8 @@ int sig_pri_load(const char *cc_type_name)
|
|||
|
||||
#if defined(HAVE_PRI_CCSS)
|
||||
sig_pri_cc_type_name = cc_type_name;
|
||||
sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
|
||||
sig_pri_cc_monitor_instance_cmp_fn);
|
||||
sig_pri_cc_monitors = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
|
||||
sig_pri_cc_monitor_instance_hash_fn, NULL, sig_pri_cc_monitor_instance_cmp_fn);
|
||||
if (!sig_pri_cc_monitors) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -90,4 +90,5 @@ SPEEX_RESAMPLE_CFLAGS:=
|
|||
endif
|
||||
|
||||
$(call MOD_ADD_C,codec_resample,speex/resample.c)
|
||||
speex/resample.o: _ASTCFLAGS+=$(SPEEX_RESAMPLE_CFLAGS)
|
||||
codec_resample.o: _ASTCFLAGS+=-DOUTSIDE_SPEEX
|
||||
speex/resample.o: _ASTCFLAGS+=$(SPEEX_RESAMPLE_CFLAGS) -DOUTSIDE_SPEEX -DEXPORT=
|
||||
|
|
|
@ -689,39 +689,37 @@ static int reload(void)
|
|||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
ast_unregister_translator(&speextolin);
|
||||
ast_unregister_translator(&lintospeex);
|
||||
ast_unregister_translator(&speexwbtolin16);
|
||||
ast_unregister_translator(&lin16tospeexwb);
|
||||
ast_unregister_translator(&speexuwbtolin32);
|
||||
ast_unregister_translator(&lin32tospeexuwb);
|
||||
|
||||
res |= ast_unregister_translator(&speextolin);
|
||||
res |= ast_unregister_translator(&lintospeex);
|
||||
res |= ast_unregister_translator(&speexwbtolin16);
|
||||
res |= ast_unregister_translator(&lin16tospeexwb);
|
||||
res |= ast_unregister_translator(&speexuwbtolin32);
|
||||
res |= ast_unregister_translator(&lin32tospeexuwb);
|
||||
|
||||
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (parse_config(0))
|
||||
if (parse_config(0)) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
/* XXX It is most likely a bug in this module if we fail to register a translator */
|
||||
res |= ast_register_translator(&speextolin);
|
||||
res |= ast_register_translator(&lintospeex);
|
||||
res |= ast_register_translator(&speexwbtolin16);
|
||||
res |= ast_register_translator(&lin16tospeexwb);
|
||||
res |= ast_register_translator(&speexuwbtolin32);
|
||||
res |= ast_register_translator(&lin32tospeexuwb);
|
||||
|
||||
if (res) {
|
||||
unload_module();
|
||||
return res;
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
return res;
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Speex Coder/Decoder",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<member name="codec_opus" displayname="Download the Opus codec from Digium. See http://downloads.digium.com/pub/telephony/codec_opus/README.">
|
||||
<support_level>external</support_level>
|
||||
<conflict>no_binary_modules</conflict>
|
||||
<depend>xmlstarlet</depend>
|
||||
<depend>bash</depend>
|
||||
<depend>res_format_attr_opus</depend>
|
||||
|
@ -7,24 +8,28 @@
|
|||
</member>
|
||||
<member name="codec_silk" displayname="Download the SILK codec from Digium. See http://downloads.digium.com/pub/telephony/codec_silk/README.">
|
||||
<support_level>external</support_level>
|
||||
<conflict>no_binary_modules</conflict>
|
||||
<depend>xmlstarlet</depend>
|
||||
<depend>bash</depend>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
</member>
|
||||
<member name="codec_siren7" displayname="Download the Siren7 codec from Digium. See http://downloads.digium.com/pub/telephony/codec_siren7/README.">
|
||||
<support_level>external</support_level>
|
||||
<conflict>no_binary_modules</conflict>
|
||||
<depend>xmlstarlet</depend>
|
||||
<depend>bash</depend>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
</member>
|
||||
<member name="codec_siren14" displayname="Download the Siren14 codec from Digium. See http://downloads.digium.com/pub/telephony/codec_siren14/README.">
|
||||
<support_level>external</support_level>
|
||||
<conflict>no_binary_modules</conflict>
|
||||
<depend>xmlstarlet</depend>
|
||||
<depend>bash</depend>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
</member>
|
||||
<member name="codec_g729a" displayname="Download the g729a codec from Digium. A license must be purchased for this codec. See http://downloads.digium.com/pub/telephony/codec_g729/README.">
|
||||
<support_level>external</support_level>
|
||||
<conflict>no_binary_modules</conflict>
|
||||
<depend>xmlstarlet</depend>
|
||||
<depend>bash</depend>
|
||||
<defaultenabled>no</defaultenabled>
|
||||
|
|
|
@ -35,14 +35,6 @@
|
|||
#ifndef ARCH_H
|
||||
#define ARCH_H
|
||||
|
||||
#ifndef SPEEX_VERSION
|
||||
#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
|
||||
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
|
||||
#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
|
||||
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
|
||||
#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
|
||||
#endif
|
||||
|
||||
#define FIXED_POINT
|
||||
|
||||
/* A couple test to catch stupid option combinations */
|
||||
|
@ -77,7 +69,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef OUTSIDE_SPEEX
|
||||
#include "speex/speex_types.h"
|
||||
#include "speex/speexdsp_types.h"
|
||||
#endif
|
||||
|
||||
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
|
||||
|
@ -91,7 +83,7 @@
|
|||
#ifdef FIXED_POINT
|
||||
|
||||
typedef spx_int16_t spx_word16_t;
|
||||
typedef spx_int32_t spx_word32_t;
|
||||
typedef spx_int32_t spx_word32_t;
|
||||
typedef spx_word32_t spx_mem_t;
|
||||
typedef spx_word16_t spx_coef_t;
|
||||
typedef spx_word16_t spx_lsp_t;
|
||||
|
@ -173,6 +165,7 @@ typedef float spx_word32_t;
|
|||
#define VSHR32(a,shift) (a)
|
||||
#define SATURATE16(x,a) (x)
|
||||
#define SATURATE32(x,a) (x)
|
||||
#define SATURATE32PSHR(x,shift,a) (x)
|
||||
|
||||
#define PSHR(a,shift) (a)
|
||||
#define SHR(a,shift) (a)
|
||||
|
|
|
@ -52,6 +52,10 @@
|
|||
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
#define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||
|
||||
#define SATURATE32PSHR(x,shift,a) (((x)>=(SHL32(a,shift))) ? (a) : \
|
||||
(x)<=-(SHL32(a,shift)) ? -(a) : \
|
||||
(PSHR32(x, shift)))
|
||||
|
||||
#define SHR(a,shift) ((a) >> (shift))
|
||||
#define SHL(a,shift) ((spx_word32_t)(a) << (shift))
|
||||
#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
|
||||
|
|
|
@ -61,18 +61,26 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef OUTSIDE_SPEEX
|
||||
#include <stdlib.h>
|
||||
static void *speex_alloc (int size) {return calloc(size,1);}
|
||||
static void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
|
||||
static void speex_free (void *ptr) {free(ptr);}
|
||||
#include "speex_resampler.h"
|
||||
#include "arch.h"
|
||||
#else /* OUTSIDE_SPEEX */
|
||||
|
||||
#include "speex/speex_resampler.h"
|
||||
#include "arch.h"
|
||||
#include "os_support.h"
|
||||
#endif /* OUTSIDE_SPEEX */
|
||||
|
||||
#include "stack_alloc.h"
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159263
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -92,6 +100,10 @@ static void speex_free (void *ptr) {free(ptr);}
|
|||
#include "resample_sse.h"
|
||||
#endif
|
||||
|
||||
#ifdef _USE_NEON
|
||||
#include "resample_neon.h"
|
||||
#endif
|
||||
|
||||
/* Numer of elements to allocate on the stack */
|
||||
#ifdef VAR_ARRAYS
|
||||
#define FIXED_STACK_ALLOC 8192
|
||||
|
@ -133,7 +145,7 @@ struct SpeexResamplerState_ {
|
|||
int out_stride;
|
||||
} ;
|
||||
|
||||
static double kaiser12_table[68] = {
|
||||
static const double kaiser12_table[68] = {
|
||||
0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076,
|
||||
0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014,
|
||||
0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601,
|
||||
|
@ -147,7 +159,7 @@ static double kaiser12_table[68] = {
|
|||
0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734,
|
||||
0.00001000, 0.00000000};
|
||||
/*
|
||||
static double kaiser12_table[36] = {
|
||||
static const double kaiser12_table[36] = {
|
||||
0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741,
|
||||
0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762,
|
||||
0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274,
|
||||
|
@ -155,7 +167,7 @@ static double kaiser12_table[36] = {
|
|||
0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291,
|
||||
0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000};
|
||||
*/
|
||||
static double kaiser10_table[36] = {
|
||||
static const double kaiser10_table[36] = {
|
||||
0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446,
|
||||
0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347,
|
||||
0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962,
|
||||
|
@ -163,7 +175,7 @@ static double kaiser10_table[36] = {
|
|||
0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739,
|
||||
0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000};
|
||||
|
||||
static double kaiser8_table[36] = {
|
||||
static const double kaiser8_table[36] = {
|
||||
0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200,
|
||||
0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126,
|
||||
0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272,
|
||||
|
@ -171,7 +183,7 @@ static double kaiser8_table[36] = {
|
|||
0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490,
|
||||
0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000};
|
||||
|
||||
static double kaiser6_table[36] = {
|
||||
static const double kaiser6_table[36] = {
|
||||
0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003,
|
||||
0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565,
|
||||
0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561,
|
||||
|
@ -180,19 +192,19 @@ static double kaiser6_table[36] = {
|
|||
0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000};
|
||||
|
||||
struct FuncDef {
|
||||
double *table;
|
||||
const double *table;
|
||||
int oversample;
|
||||
};
|
||||
|
||||
static struct FuncDef _KAISER12 = {kaiser12_table, 64};
|
||||
static const struct FuncDef _KAISER12 = {kaiser12_table, 64};
|
||||
#define KAISER12 (&_KAISER12)
|
||||
/*static struct FuncDef _KAISER12 = {kaiser12_table, 32};
|
||||
#define KAISER12 (&_KAISER12)*/
|
||||
static struct FuncDef _KAISER10 = {kaiser10_table, 32};
|
||||
static const struct FuncDef _KAISER10 = {kaiser10_table, 32};
|
||||
#define KAISER10 (&_KAISER10)
|
||||
static struct FuncDef _KAISER8 = {kaiser8_table, 32};
|
||||
static const struct FuncDef _KAISER8 = {kaiser8_table, 32};
|
||||
#define KAISER8 (&_KAISER8)
|
||||
static struct FuncDef _KAISER6 = {kaiser6_table, 32};
|
||||
static const struct FuncDef _KAISER6 = {kaiser6_table, 32};
|
||||
#define KAISER6 (&_KAISER6)
|
||||
|
||||
struct QualityMapping {
|
||||
|
@ -200,7 +212,7 @@ struct QualityMapping {
|
|||
int oversample;
|
||||
float downsample_bandwidth;
|
||||
float upsample_bandwidth;
|
||||
struct FuncDef *window_func;
|
||||
const struct FuncDef *window_func;
|
||||
};
|
||||
|
||||
|
||||
|
@ -227,7 +239,7 @@ static const struct QualityMapping quality_map[11] = {
|
|||
{256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */
|
||||
};
|
||||
/*8,24,40,56,80,104,128,160,200,256,320*/
|
||||
static double compute_func(float x, struct FuncDef *func)
|
||||
static double compute_func(float x, const struct FuncDef *func)
|
||||
{
|
||||
float y, frac;
|
||||
double interp[4];
|
||||
|
@ -262,7 +274,7 @@ int main(int argc, char **argv)
|
|||
|
||||
#ifdef FIXED_POINT
|
||||
/* The slow way of computing a sinc for the table. Should improve that some day */
|
||||
static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
|
||||
static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func)
|
||||
{
|
||||
/*fprintf (stderr, "%f ", x);*/
|
||||
float xx = x * cutoff;
|
||||
|
@ -275,7 +287,7 @@ static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_fu
|
|||
}
|
||||
#else
|
||||
/* The slow way of computing a sinc for the table. Should improve that some day */
|
||||
static spx_word16_t sinc(float cutoff, float x, int N, struct FuncDef *window_func)
|
||||
static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func)
|
||||
{
|
||||
/*fprintf (stderr, "%f ", x);*/
|
||||
float xx = x * cutoff;
|
||||
|
@ -330,28 +342,35 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c
|
|||
const int frac_advance = st->frac_advance;
|
||||
const spx_uint32_t den_rate = st->den_rate;
|
||||
spx_word32_t sum;
|
||||
int j;
|
||||
|
||||
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
|
||||
{
|
||||
const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
|
||||
const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];
|
||||
const spx_word16_t *iptr = & in[last_sample];
|
||||
|
||||
#ifndef OVERRIDE_INNER_PRODUCT_SINGLE
|
||||
float accum[4] = {0,0,0,0};
|
||||
int j;
|
||||
sum = 0;
|
||||
for(j=0;j<N;j++) sum += MULT16_16(sinct[j], iptr[j]);
|
||||
|
||||
/* This code is slower on most DSPs which have only 2 accumulators.
|
||||
Plus this this forces truncation to 32 bits and you lose the HW guard bits.
|
||||
I think we can trust the compiler and let it vectorize and/or unroll itself.
|
||||
spx_word32_t accum[4] = {0,0,0,0};
|
||||
for(j=0;j<N;j+=4) {
|
||||
accum[0] += sinc[j]*iptr[j];
|
||||
accum[1] += sinc[j+1]*iptr[j+1];
|
||||
accum[2] += sinc[j+2]*iptr[j+2];
|
||||
accum[3] += sinc[j+3]*iptr[j+3];
|
||||
accum[0] += MULT16_16(sinct[j], iptr[j]);
|
||||
accum[1] += MULT16_16(sinct[j+1], iptr[j+1]);
|
||||
accum[2] += MULT16_16(sinct[j+2], iptr[j+2]);
|
||||
accum[3] += MULT16_16(sinct[j+3], iptr[j+3]);
|
||||
}
|
||||
sum = accum[0] + accum[1] + accum[2] + accum[3];
|
||||
*/
|
||||
sum = SATURATE32PSHR(sum, 15, 32767);
|
||||
#else
|
||||
sum = inner_product_single(sinc, iptr, N);
|
||||
sum = inner_product_single(sinct, iptr, N);
|
||||
#endif
|
||||
|
||||
out[out_stride * out_sample++] = PSHR32(sum, 15);
|
||||
out[out_stride * out_sample++] = sum;
|
||||
last_sample += int_advance;
|
||||
samp_frac_num += frac_advance;
|
||||
if (samp_frac_num >= den_rate)
|
||||
|
@ -381,25 +400,25 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c
|
|||
const int frac_advance = st->frac_advance;
|
||||
const spx_uint32_t den_rate = st->den_rate;
|
||||
double sum;
|
||||
int j;
|
||||
|
||||
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
|
||||
{
|
||||
const spx_word16_t *sinc = & sinc_table[samp_frac_num*N];
|
||||
const spx_word16_t *sinct = & sinc_table[samp_frac_num*N];
|
||||
const spx_word16_t *iptr = & in[last_sample];
|
||||
|
||||
#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE
|
||||
int j;
|
||||
double accum[4] = {0,0,0,0};
|
||||
|
||||
for(j=0;j<N;j+=4) {
|
||||
accum[0] += sinc[j]*iptr[j];
|
||||
accum[1] += sinc[j+1]*iptr[j+1];
|
||||
accum[2] += sinc[j+2]*iptr[j+2];
|
||||
accum[3] += sinc[j+3]*iptr[j+3];
|
||||
accum[0] += sinct[j]*iptr[j];
|
||||
accum[1] += sinct[j+1]*iptr[j+1];
|
||||
accum[2] += sinct[j+2]*iptr[j+2];
|
||||
accum[3] += sinct[j+3]*iptr[j+3];
|
||||
}
|
||||
sum = accum[0] + accum[1] + accum[2] + accum[3];
|
||||
#else
|
||||
sum = inner_product_double(sinc, iptr, N);
|
||||
sum = inner_product_double(sinct, iptr, N);
|
||||
#endif
|
||||
|
||||
out[out_stride * out_sample++] = PSHR32(sum, 15);
|
||||
|
@ -428,7 +447,6 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3
|
|||
const int int_advance = st->int_advance;
|
||||
const int frac_advance = st->frac_advance;
|
||||
const spx_uint32_t den_rate = st->den_rate;
|
||||
int j;
|
||||
spx_word32_t sum;
|
||||
|
||||
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
|
||||
|
@ -445,6 +463,7 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3
|
|||
|
||||
|
||||
#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
|
||||
int j;
|
||||
spx_word32_t accum[4] = {0,0,0,0};
|
||||
|
||||
for(j=0;j<N;j++) {
|
||||
|
@ -456,13 +475,14 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3
|
|||
}
|
||||
|
||||
cubic_coef(frac, interp);
|
||||
sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
|
||||
sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1));
|
||||
sum = SATURATE32PSHR(sum, 15, 32767);
|
||||
#else
|
||||
cubic_coef(frac, interp);
|
||||
sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
|
||||
#endif
|
||||
|
||||
out[out_stride * out_sample++] = PSHR32(sum,15);
|
||||
out[out_stride * out_sample++] = sum;
|
||||
last_sample += int_advance;
|
||||
samp_frac_num += frac_advance;
|
||||
if (samp_frac_num >= den_rate)
|
||||
|
@ -490,7 +510,6 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3
|
|||
const int int_advance = st->int_advance;
|
||||
const int frac_advance = st->frac_advance;
|
||||
const spx_uint32_t den_rate = st->den_rate;
|
||||
int j;
|
||||
spx_word32_t sum;
|
||||
|
||||
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
|
||||
|
@ -507,6 +526,7 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3
|
|||
|
||||
|
||||
#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE
|
||||
int j;
|
||||
double accum[4] = {0,0,0,0};
|
||||
|
||||
for(j=0;j<N;j++) {
|
||||
|
@ -540,11 +560,47 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3
|
|||
}
|
||||
#endif
|
||||
|
||||
static void update_filter(SpeexResamplerState *st)
|
||||
/* This resampler is used to produce zero output in situations where memory
|
||||
for the filter could not be allocated. The expected numbers of input and
|
||||
output samples are still processed so that callers failing to check error
|
||||
codes are not surprised, possibly getting into infinite loops. */
|
||||
static int resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len)
|
||||
{
|
||||
spx_uint32_t old_length;
|
||||
int out_sample = 0;
|
||||
int last_sample = st->last_sample[channel_index];
|
||||
spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index];
|
||||
const int out_stride = st->out_stride;
|
||||
const int int_advance = st->int_advance;
|
||||
const int frac_advance = st->frac_advance;
|
||||
const spx_uint32_t den_rate = st->den_rate;
|
||||
|
||||
old_length = st->filt_len;
|
||||
while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len))
|
||||
{
|
||||
out[out_stride * out_sample++] = 0;
|
||||
last_sample += int_advance;
|
||||
samp_frac_num += frac_advance;
|
||||
if (samp_frac_num >= den_rate)
|
||||
{
|
||||
samp_frac_num -= den_rate;
|
||||
last_sample++;
|
||||
}
|
||||
}
|
||||
|
||||
st->last_sample[channel_index] = last_sample;
|
||||
st->samp_frac_num[channel_index] = samp_frac_num;
|
||||
return out_sample;
|
||||
}
|
||||
|
||||
static int update_filter(SpeexResamplerState *st)
|
||||
{
|
||||
spx_uint32_t old_length = st->filt_len;
|
||||
spx_uint32_t old_alloc_size = st->mem_alloc_size;
|
||||
int use_direct;
|
||||
spx_uint32_t min_sinc_table_length;
|
||||
spx_uint32_t min_alloc_size;
|
||||
|
||||
st->int_advance = st->num_rate/st->den_rate;
|
||||
st->frac_advance = st->num_rate%st->den_rate;
|
||||
st->oversample = quality_map[st->quality].oversample;
|
||||
st->filt_len = quality_map[st->quality].base_length;
|
||||
|
||||
|
@ -554,8 +610,8 @@ static void update_filter(SpeexResamplerState *st)
|
|||
st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
|
||||
/* FIXME: divide the numerator and denominator by a certain amount if they're too large */
|
||||
st->filt_len = st->filt_len*st->num_rate / st->den_rate;
|
||||
/* Round down to make sure we have a multiple of 4 */
|
||||
st->filt_len &= (~0x3);
|
||||
/* Round up to make sure we have a multiple of 8 for SSE */
|
||||
st->filt_len = ((st->filt_len-1)&(~0x7))+8;
|
||||
if (2*st->den_rate < st->num_rate)
|
||||
st->oversample >>= 1;
|
||||
if (4*st->den_rate < st->num_rate)
|
||||
|
@ -572,16 +628,35 @@ static void update_filter(SpeexResamplerState *st)
|
|||
}
|
||||
|
||||
/* Choose the resampling type that requires the least amount of memory */
|
||||
if (st->den_rate <= st->oversample)
|
||||
#ifdef RESAMPLE_FULL_SINC_TABLE
|
||||
use_direct = 1;
|
||||
if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len)
|
||||
goto fail;
|
||||
#else
|
||||
use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8
|
||||
&& INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len;
|
||||
#endif
|
||||
if (use_direct)
|
||||
{
|
||||
min_sinc_table_length = st->filt_len*st->den_rate;
|
||||
} else {
|
||||
if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len)
|
||||
goto fail;
|
||||
|
||||
min_sinc_table_length = st->filt_len*st->oversample+8;
|
||||
}
|
||||
if (st->sinc_table_length < min_sinc_table_length)
|
||||
{
|
||||
spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t));
|
||||
if (!sinc_table)
|
||||
goto fail;
|
||||
|
||||
st->sinc_table = sinc_table;
|
||||
st->sinc_table_length = min_sinc_table_length;
|
||||
}
|
||||
if (use_direct)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
if (!st->sinc_table)
|
||||
st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
|
||||
else if (st->sinc_table_length < st->filt_len*st->den_rate)
|
||||
{
|
||||
st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
|
||||
st->sinc_table_length = st->filt_len*st->den_rate;
|
||||
}
|
||||
for (i=0;i<st->den_rate;i++)
|
||||
{
|
||||
spx_int32_t j;
|
||||
|
@ -601,13 +676,6 @@ static void update_filter(SpeexResamplerState *st)
|
|||
/*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
|
||||
} else {
|
||||
spx_int32_t i;
|
||||
if (!st->sinc_table)
|
||||
st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
|
||||
else if (st->sinc_table_length < st->filt_len*st->oversample+8)
|
||||
{
|
||||
st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
|
||||
st->sinc_table_length = st->filt_len*st->oversample+8;
|
||||
}
|
||||
for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
|
||||
st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -620,43 +688,39 @@ static void update_filter(SpeexResamplerState *st)
|
|||
#endif
|
||||
/*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
|
||||
}
|
||||
st->int_advance = st->num_rate/st->den_rate;
|
||||
st->frac_advance = st->num_rate%st->den_rate;
|
||||
|
||||
|
||||
/* Here's the place where we update the filter memory to take into account
|
||||
the change in filter length. It's probably the messiest part of the code
|
||||
due to handling of lots of corner cases. */
|
||||
if (!st->mem)
|
||||
|
||||
/* Adding buffer_size to filt_len won't overflow here because filt_len
|
||||
could be multiplied by sizeof(spx_word16_t) above. */
|
||||
min_alloc_size = st->filt_len-1 + st->buffer_size;
|
||||
if (min_alloc_size > st->mem_alloc_size)
|
||||
{
|
||||
spx_word16_t *mem;
|
||||
if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size)
|
||||
goto fail;
|
||||
else if (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem))))
|
||||
goto fail;
|
||||
|
||||
st->mem = mem;
|
||||
st->mem_alloc_size = min_alloc_size;
|
||||
}
|
||||
if (!st->started)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
|
||||
st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
|
||||
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
|
||||
st->mem[i] = 0;
|
||||
/*speex_warning("init filter");*/
|
||||
} else if (!st->started)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
|
||||
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
|
||||
for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
|
||||
st->mem[i] = 0;
|
||||
/*speex_warning("reinit filter");*/
|
||||
} else if (st->filt_len > old_length)
|
||||
{
|
||||
spx_int32_t i;
|
||||
spx_uint32_t i;
|
||||
/* Increase the filter length */
|
||||
/*speex_warning("increase filter size");*/
|
||||
int old_alloc_size = st->mem_alloc_size;
|
||||
if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size)
|
||||
for (i=st->nb_channels;i--;)
|
||||
{
|
||||
st->mem_alloc_size = st->filt_len-1 + st->buffer_size;
|
||||
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t));
|
||||
}
|
||||
for (i=st->nb_channels-1;i>=0;i--)
|
||||
{
|
||||
spx_int32_t j;
|
||||
spx_uint32_t j;
|
||||
spx_uint32_t olen = old_length;
|
||||
/*if (st->magic_samples[i])*/
|
||||
{
|
||||
|
@ -664,7 +728,7 @@ static void update_filter(SpeexResamplerState *st)
|
|||
|
||||
/* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
|
||||
olen = old_length + 2*st->magic_samples[i];
|
||||
for (j=old_length-2+st->magic_samples[i];j>=0;j--)
|
||||
for (j=old_length-1+st->magic_samples[i];j--;)
|
||||
st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];
|
||||
for (j=0;j<st->magic_samples[i];j++)
|
||||
st->mem[i*st->mem_alloc_size+j] = 0;
|
||||
|
@ -705,18 +769,28 @@ static void update_filter(SpeexResamplerState *st)
|
|||
st->magic_samples[i] += old_magic;
|
||||
}
|
||||
}
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
|
||||
fail:
|
||||
st->resampler_ptr = resampler_basic_zero;
|
||||
/* st->mem may still contain consumed input samples for the filter.
|
||||
Restore filt_len so that filt_len - 1 still points to the position after
|
||||
the last of these samples. */
|
||||
st->filt_len = old_length;
|
||||
return RESAMPLER_ERR_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
|
||||
EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
|
||||
{
|
||||
return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err);
|
||||
}
|
||||
|
||||
SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
|
||||
EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
SpeexResamplerState *st;
|
||||
int filter_err;
|
||||
|
||||
if (quality > 10 || quality < 0)
|
||||
{
|
||||
if (err)
|
||||
|
@ -742,16 +816,12 @@ static void update_filter(SpeexResamplerState *st)
|
|||
st->in_stride = 1;
|
||||
st->out_stride = 1;
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
st->buffer_size = 160;
|
||||
#else
|
||||
st->buffer_size = 160;
|
||||
#endif
|
||||
|
||||
/* Per channel data */
|
||||
st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int));
|
||||
st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
|
||||
st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int));
|
||||
st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t));
|
||||
st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t));
|
||||
for (i=0;i<nb_channels;i++)
|
||||
{
|
||||
st->last_sample[i] = 0;
|
||||
|
@ -762,17 +832,21 @@ static void update_filter(SpeexResamplerState *st)
|
|||
speex_resampler_set_quality(st, quality);
|
||||
speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate);
|
||||
|
||||
|
||||
update_filter(st);
|
||||
|
||||
st->initialised = 1;
|
||||
filter_err = update_filter(st);
|
||||
if (filter_err == RESAMPLER_ERR_SUCCESS)
|
||||
{
|
||||
st->initialised = 1;
|
||||
} else {
|
||||
speex_resampler_destroy(st);
|
||||
st = NULL;
|
||||
}
|
||||
if (err)
|
||||
*err = RESAMPLER_ERR_SUCCESS;
|
||||
*err = filter_err;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
void speex_resampler_destroy(SpeexResamplerState *st)
|
||||
EXPORT void speex_resampler_destroy(SpeexResamplerState *st)
|
||||
{
|
||||
speex_free(st->mem);
|
||||
speex_free(st->sinc_table);
|
||||
|
@ -829,9 +903,9 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
#else
|
||||
int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
#endif
|
||||
{
|
||||
int j;
|
||||
|
@ -866,13 +940,13 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
}
|
||||
*in_len -= ilen;
|
||||
*out_len -= olen;
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
#else
|
||||
int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
#endif
|
||||
{
|
||||
int j;
|
||||
|
@ -940,20 +1014,22 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
*in_len -= ilen;
|
||||
*out_len -= olen;
|
||||
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
int istride_save, ostride_save;
|
||||
spx_uint32_t bak_len = *out_len;
|
||||
spx_uint32_t bak_out_len = *out_len;
|
||||
spx_uint32_t bak_in_len = *in_len;
|
||||
istride_save = st->in_stride;
|
||||
ostride_save = st->out_stride;
|
||||
st->in_stride = st->out_stride = st->nb_channels;
|
||||
for (i=0;i<st->nb_channels;i++)
|
||||
{
|
||||
*out_len = bak_len;
|
||||
*out_len = bak_out_len;
|
||||
*in_len = bak_in_len;
|
||||
if (in != NULL)
|
||||
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
|
||||
else
|
||||
|
@ -961,20 +1037,22 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
}
|
||||
st->in_stride = istride_save;
|
||||
st->out_stride = ostride_save;
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
int istride_save, ostride_save;
|
||||
spx_uint32_t bak_len = *out_len;
|
||||
spx_uint32_t bak_out_len = *out_len;
|
||||
spx_uint32_t bak_in_len = *in_len;
|
||||
istride_save = st->in_stride;
|
||||
ostride_save = st->out_stride;
|
||||
st->in_stride = st->out_stride = st->nb_channels;
|
||||
for (i=0;i<st->nb_channels;i++)
|
||||
{
|
||||
*out_len = bak_len;
|
||||
*out_len = bak_out_len;
|
||||
*in_len = bak_in_len;
|
||||
if (in != NULL)
|
||||
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
|
||||
else
|
||||
|
@ -982,21 +1060,21 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
}
|
||||
st->in_stride = istride_save;
|
||||
st->out_stride = ostride_save;
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
|
||||
EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate)
|
||||
{
|
||||
return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate);
|
||||
}
|
||||
|
||||
void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
|
||||
EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate)
|
||||
{
|
||||
*in_rate = st->in_rate;
|
||||
*out_rate = st->out_rate;
|
||||
}
|
||||
|
||||
int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
|
||||
EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate)
|
||||
{
|
||||
spx_uint32_t fact;
|
||||
spx_uint32_t old_den;
|
||||
|
@ -1031,17 +1109,17 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
}
|
||||
|
||||
if (st->initialised)
|
||||
update_filter(st);
|
||||
return update_filter(st);
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
|
||||
EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den)
|
||||
{
|
||||
*ratio_num = st->num_rate;
|
||||
*ratio_den = st->den_rate;
|
||||
}
|
||||
|
||||
int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
|
||||
EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality)
|
||||
{
|
||||
if (quality > 10 || quality < 0)
|
||||
return RESAMPLER_ERR_INVALID_ARG;
|
||||
|
@ -1049,46 +1127,46 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
return RESAMPLER_ERR_SUCCESS;
|
||||
st->quality = quality;
|
||||
if (st->initialised)
|
||||
update_filter(st);
|
||||
return update_filter(st);
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
|
||||
EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality)
|
||||
{
|
||||
*quality = st->quality;
|
||||
}
|
||||
|
||||
void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
|
||||
EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride)
|
||||
{
|
||||
st->in_stride = stride;
|
||||
}
|
||||
|
||||
void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
|
||||
EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride)
|
||||
{
|
||||
*stride = st->in_stride;
|
||||
}
|
||||
|
||||
void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
|
||||
EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride)
|
||||
{
|
||||
st->out_stride = stride;
|
||||
}
|
||||
|
||||
void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
|
||||
EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride)
|
||||
{
|
||||
*stride = st->out_stride;
|
||||
}
|
||||
|
||||
int speex_resampler_get_input_latency(SpeexResamplerState *st)
|
||||
EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st)
|
||||
{
|
||||
return st->filt_len / 2;
|
||||
}
|
||||
|
||||
int speex_resampler_get_output_latency(SpeexResamplerState *st)
|
||||
EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st)
|
||||
{
|
||||
return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate;
|
||||
}
|
||||
|
||||
int speex_resampler_skip_zeros(SpeexResamplerState *st)
|
||||
EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
for (i=0;i<st->nb_channels;i++)
|
||||
|
@ -1096,15 +1174,21 @@ static int speex_resampler_magic(SpeexResamplerState *st, spx_uint32_t channel_i
|
|||
return RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
int speex_resampler_reset_mem(SpeexResamplerState *st)
|
||||
EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
|
||||
{
|
||||
spx_uint32_t i;
|
||||
for (i=0;i<st->nb_channels;i++)
|
||||
{
|
||||
st->last_sample[i] = 0;
|
||||
st->magic_samples[i] = 0;
|
||||
st->samp_frac_num[i] = 0;
|
||||
}
|
||||
for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
|
||||
st->mem[i] = 0;
|
||||
return RESAMPLER_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
const char *speex_resampler_strerror(int err)
|
||||
EXPORT const char *speex_resampler_strerror(int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
|
|
|
@ -39,8 +39,6 @@
|
|||
#ifndef SPEEX_RESAMPLER_H
|
||||
#define SPEEX_RESAMPLER_H
|
||||
|
||||
#define OUTSIDE_SPEEX
|
||||
|
||||
#ifdef OUTSIDE_SPEEX
|
||||
|
||||
/********* WARNING: MENTAL SANITY ENDS HERE *************/
|
||||
|
@ -48,7 +46,7 @@
|
|||
/* If the resampler is defined outside of Speex, we change the symbol names so that
|
||||
there won't be any clash if linking with Speex later on. */
|
||||
|
||||
#define RANDOM_PREFIX ast
|
||||
#define RANDOM_PREFIX speex
|
||||
#ifndef RANDOM_PREFIX
|
||||
#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -62,6 +62,7 @@ load = pbx_config.so
|
|||
|
||||
; Resources
|
||||
|
||||
load = res_http_websocket.so
|
||||
load = res_musiconhold.so
|
||||
load = res_pjproject.so
|
||||
load = res_pjsip_acl.so
|
||||
|
@ -92,7 +93,6 @@ load = res_pjsip_pidf_eyebeam_body_supplement.so
|
|||
load = res_pjsip_publish_asterisk.so
|
||||
load = res_pjsip_pubsub.so
|
||||
load = res_pjsip_refer.so
|
||||
load = res_pjsip_registrar_expire.so
|
||||
load = res_pjsip_registrar.so
|
||||
load = res_pjsip_rfc3326.so
|
||||
load = res_pjsip_sdp_rtp.so
|
||||
|
@ -108,3 +108,9 @@ load = res_sorcery_config.so
|
|||
load = res_sorcery_memory.so
|
||||
load = res_sorcery_realtime.so
|
||||
load = res_timing_timerfd.so
|
||||
|
||||
; Don't load res_hep.so and kin unless you are using hep monitoring in your network
|
||||
|
||||
noload = res_hep.so
|
||||
noload = res_hep_pjsip.so
|
||||
noload = res_hep_rtcp.so
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
; rfc3842
|
||||
; put empty "Content=>" at the end to have CRLF after last body line
|
||||
|
||||
[clear-mwi]
|
||||
Event=>message-summary
|
||||
Content-type=>application/simple-message-summary
|
||||
Content=>Messages-Waiting: no
|
||||
Content=>Message-Account: sip:asterisk@127.0.0.1
|
||||
Content=>Voice-Message: 0/0 (0/0)
|
||||
Content=>
|
||||
|
||||
; Aastra
|
||||
|
||||
[aastra-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
[aastra-xml]
|
||||
Event=>aastra-xml
|
||||
|
||||
; Digium
|
||||
|
||||
[digium-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Linksys
|
||||
|
||||
[linksys-cold-restart]
|
||||
Event=>reboot_now
|
||||
|
||||
[linksys-warm-restart]
|
||||
Event=>restart_now
|
||||
|
||||
; Polycom
|
||||
|
||||
[polycom-check-cfg]
|
||||
Event=>check-sync
|
||||
|
||||
; Sipura
|
||||
|
||||
[sipura-check-cfg]
|
||||
Event=>resync
|
||||
|
||||
[sipura-get-report]
|
||||
Event=>report
|
||||
|
||||
; snom
|
||||
|
||||
[snom-check-cfg]
|
||||
Event=>check-sync\;reboot=false
|
||||
|
||||
[snom-reboot]
|
||||
Event=>check-sync\;reboot=true
|
||||
|
||||
; Cisco
|
||||
|
||||
[cisco-check-cfg]
|
||||
Event=>check-sync
|
|
@ -164,6 +164,11 @@ packetloss_percentage=10;
|
|||
|
||||
;============================ OPUS Section Options ============================
|
||||
;
|
||||
; NOTE: Accurate documentation corresponding to your downloaded version of
|
||||
; codec_opus is available from Asterisk's CLI:
|
||||
;
|
||||
; *CLI> config show help codec_opus opus
|
||||
;
|
||||
;[opus]
|
||||
;type= ; Must be of type "opus" (default: "")
|
||||
;packet_loss= ; Encoder's packet loss percentage. Can be any number between 0
|
||||
|
@ -182,35 +187,28 @@ packetloss_percentage=10;
|
|||
;max_playback_rate= ; Override the maximum playback rate in the offer's SDP.
|
||||
; Any value between 8000 and 48000 (inclusive) is valid,
|
||||
; however typically it should match one of the usual opus
|
||||
; bandwidths. A value of "sdp" is also allowed. When set
|
||||
; to "sdp" then the value from the offer's SDP is used.
|
||||
; (default: "sdp")
|
||||
; bandwidths. (default: 48000)
|
||||
;bitrate= ; Override the maximum average bitrate in the offer's SDP. Any value
|
||||
; between 500 and 512000 is valid. The following values are also
|
||||
; allowed: auto, max, sdp. When set to "sdp" then the value from
|
||||
; the offer's sdp is used. (default: "sdp")
|
||||
; allowed: auto, max. (default: auto)
|
||||
;cbr= ; Override the constant bit rate parameter in the offer's SDP. A value of
|
||||
; 0/false/no represents a variable bit rate whereas 1/true/yes represents
|
||||
; a constant bit rate. A value of "sdp" is also allowed. When set to "sdp"
|
||||
; then the value from the offer's sdp is used. (default: "sdp")
|
||||
; a constant bit rate. (default: no)
|
||||
;fec= ; Override the use inband fec parameter in the offer's SDP. A value of
|
||||
; 0/false/no represents disabled whereas 1/true/yes represents enabled.
|
||||
; A value of "sdp" is also allowed. When set to "sdp" then the value from
|
||||
; the offer's sdp is used. (default: "sdp")
|
||||
; (default: yes)
|
||||
;dtx= ; Override the use dtx parameter in the offer's SDP. A value of 0/false/no
|
||||
; represents disabled whereas 1/true/yes represents enabled. A value of
|
||||
; "sdp" is also allowed. When set to "sdp" then the value from the offer's
|
||||
; sdp is used. (default: "sdp")
|
||||
; represents disabled whereas 1/true/yes represents enabled. (default: no)
|
||||
|
||||
;=============================== OPUS Examples ================================
|
||||
;
|
||||
;[opus]
|
||||
;type=opus
|
||||
;max_playback_rate=8000 ; Limit the maximum playback rate on the encoder
|
||||
;fec=no ; Force no inband fec on the encoder (i.e don't use what's on the SDP)
|
||||
;fec=no ; No inband fec
|
||||
|
||||
;[myopus]
|
||||
;type=opus
|
||||
;max_bandwidth=wide ; Maximum encoded bandwidth set to wide band (0-8000 Hz
|
||||
; ; audio bandwidth at 16Khz sample rate)
|
||||
;cbr=yes ; Force a constant bit rate (i.e don't use what's on the SDP)
|
||||
;cbr=yes ; Negotiate a constant bit rate
|
||||
|
|
|
@ -254,7 +254,11 @@ type=bridge
|
|||
;remb_behavior=average ; How the combined REMB report for an SFU video bridge is constructed. If set to "average" then
|
||||
; the estimated maximum bitrate of each receiver is used to construct an average bitrate. If
|
||||
; set to "lowest" the lowest maximum bitrate is forwarded to the sender. If set to "highest"
|
||||
; the highest maximum bitrate is forwarded to the sender. This defaults to "average".
|
||||
; the highest maximum bitrate is forwarded to the sender. If set to "average_all" a single average
|
||||
; is generated from every receiver and the same value is sent to every sender. If set to
|
||||
; "lowest_all" the lowest maximum bitrate of all receivers is sent to every sender. If set to
|
||||
; "highest_all" the highest maximum bitrate of all receivers is sent to every sender. This
|
||||
; defaults to "average".
|
||||
|
||||
;enable_events=no ; If enabled, recipients who joined the bridge via a channel driver
|
||||
; that supports Enhanced Messaging (currently only chan_pjsip) will
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
;phone=+12565551212
|
||||
;
|
||||
;
|
||||
; Specify bind address and port number. Default is
|
||||
; 4520
|
||||
; Specify bind address. IPv6 addresses are accepted. Default is 0.0.0.0
|
||||
; You can specify 'bindaddr2' to bind to another address however
|
||||
; 'bindaddr and 'bindaddr2' need to be different IP protocols.
|
||||
; Specify port number. Default is 4520.
|
||||
;
|
||||
;bindaddr=0.0.0.0
|
||||
;port=4520
|
||||
|
@ -30,27 +32,27 @@
|
|||
; See https://wiki.asterisk.org/wiki/display/AST/IP+Quality+of+Service for a description of the tos parameter.
|
||||
;tos=ef
|
||||
;
|
||||
; Our entity identifier (Should generally be the MAC address of the
|
||||
; Our entity identifier. (It should generally be the MAC address of the
|
||||
; machine it's running on. Defaults to the first eth address, but you
|
||||
; can override it here, as long as you set it to the MAC of *something*
|
||||
; you own!) The EID can be overridden by a setting in asterisk.conf,
|
||||
; you own!) The EID can be overridden by a setting in asterisk.conf
|
||||
; or by setting this option.
|
||||
;
|
||||
;entityid=00:07:E9:3B:76:60
|
||||
;
|
||||
; Peers shall cache our query responses for the specified time,
|
||||
; given in seconds. Default is 3600.
|
||||
; Peers shall cache our query responses for the specified time
|
||||
; in seconds. Default is 3600.
|
||||
;
|
||||
;cachetime=3600
|
||||
;
|
||||
; This defines the max depth in which to search the DUNDi system.
|
||||
; This defines the max depth (hops) in which to search the DUNDi system.
|
||||
; Note that the maximum time that we will wait for a response is
|
||||
; (2000 + 200 * ttl) ms.
|
||||
;
|
||||
ttl=32
|
||||
;
|
||||
; If we don't get ACK to our DPDISCOVER within 2000ms, and autokill is set
|
||||
; to yes, then we cancel the whole thing (that's enough time for one
|
||||
; If we don't get ACK to our DPDISCOVER within 2000ms and autokill is set
|
||||
; to yes then we cancel the whole thing (that's enough time for one
|
||||
; retransmission only). This is used to keep things from stalling for a long
|
||||
; time for a host that is not available, but would be ill advised for bad
|
||||
; connections. In addition to 'yes' or 'no' you can also specify a number
|
||||
|
@ -66,7 +68,7 @@ autokill=yes
|
|||
;secretpath=dundi
|
||||
;
|
||||
; The 'storehistory' option (also changeable at runtime with
|
||||
; 'dundi store history' and 'dundi no store history') will
|
||||
; 'dundi store history on' and 'dundi store history off') will
|
||||
; cause the DUNDi engine to keep track of the last several
|
||||
; queries and the amount of time each query took to execute
|
||||
; for the purpose of tracking slow nodes. This option is
|
||||
|
@ -83,7 +85,7 @@ autokill=yes
|
|||
; Agreement (GPA) if you are a member of the DUNDi E.164
|
||||
; Peering System.
|
||||
;
|
||||
; dundi_context => local_context,weight,tech,dest[,options]]
|
||||
; dundi_context => [local_context,weight,tech,dest{,options}]
|
||||
;
|
||||
; 'dundi_context' is the name of the context being requested
|
||||
; within the DUNDi request
|
||||
|
@ -97,14 +99,14 @@ autokill=yes
|
|||
; with a lower weight are tried first. Note that the weight has a
|
||||
; special meaning in the e164 context - see the GPA for more details.
|
||||
;
|
||||
; 'tech' is the technology to use (IAX, SIP, H323)
|
||||
; 'tech' is the technology to use (IAX2, SIP, H323)
|
||||
;
|
||||
; 'dest' is the destination to supply for reaching that number. The
|
||||
; following variables can be used in the destination string and will
|
||||
; be automatically substituted:
|
||||
; 'dest' is the Dial application's channel technology resource destination
|
||||
; to supply for reaching that number. The following variables can be used
|
||||
; in the destination string and will be automatically substituted:
|
||||
; ${NUMBER}: The number being requested
|
||||
; ${IPADDR}: The IP address to connect to
|
||||
; ${SECRET}: The current rotating secret key to be used
|
||||
; ${SECRET}: The current IAX2 rotating secret key to be used
|
||||
;
|
||||
; Further options may include:
|
||||
;
|
||||
|
@ -122,12 +124,13 @@ autokill=yes
|
|||
; There *must* exist an entry in mappings for DUNDi to respond
|
||||
; to any request, although it may be empty.
|
||||
;
|
||||
;empty_context =>
|
||||
;
|
||||
;e164 => dundi-e164-canonical,0,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
|
||||
;e164 => dundi-e164-customers,100,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
|
||||
;e164 => dundi-e164-via-pstn,400,IAX2,dundi:${SECRET}@${IPADDR}/${NUMBER},nounsolicited,nocomunsolicit,nopartial
|
||||
|
||||
;
|
||||
;digexten => default,0,IAX2,guest@lappy/${NUMBER}
|
||||
;asdf =>
|
||||
|
||||
;
|
||||
; Weights for mappings can be set a few different ways:
|
||||
|
@ -140,35 +143,35 @@ autokill=yes
|
|||
;
|
||||
; 3) It can be retrieved using a dialplan function. This can be extremely
|
||||
; useful if you want to let an external script decide what the weight
|
||||
; in a response shouuld be.
|
||||
; in a response should be.
|
||||
;testmap3 => context3,${SHELL(echo 123)},IAX2,guest@peer3/${NUMBER}
|
||||
;
|
||||
; The built in variables ${SECRET}, ${IPADDR} and ${NUMBER} can also be
|
||||
; passed to the weight. For example, you could pass the ${NUMBER} value
|
||||
; to your SHELL() script and use that to dynamically return a weight.
|
||||
;
|
||||
; Note than when using a global variable or dialplan function to set the
|
||||
; weight for a mapping, that response caching should be disabled if you
|
||||
; Note when using a global variable or dialplan function to set the
|
||||
; weight for a mapping that response caching should be disabled if you
|
||||
; plan for these values to change frequently at all. If the results are
|
||||
; cached, then any change in value will not take effect until the cache
|
||||
; cached then any change in value will not take effect until the cache
|
||||
; has expired.
|
||||
;
|
||||
|
||||
;
|
||||
; The remaining sections represent the peers
|
||||
; that we fundamentally trust. The section name
|
||||
; represents the name and optionally at a specific
|
||||
; DUNDi context if you want the trust to be established
|
||||
; for only a specific DUNDi context.
|
||||
; The remaining sections represent the peers that we fundamentally trust.
|
||||
; The section name specifies the peer's entityid. You can specify which
|
||||
; DUNDi contexts with which you want the trust to be established.
|
||||
;
|
||||
; inkey - What key they will be authenticating to us with
|
||||
;
|
||||
; outkey - What key we use to authenticate to them
|
||||
;
|
||||
; host - What their host is
|
||||
; host - What their host is (DNS name, IP address, or dynamic)
|
||||
;
|
||||
; port - The port where their host is listening (default: 4520)
|
||||
;
|
||||
; ustothem - Explicitly specify the entityid we use with this peer.
|
||||
;
|
||||
; order - What search order to use. May be 'primary', 'secondary',
|
||||
; 'tertiary' or 'quartiary'. In large systems, it is beneficial
|
||||
; to only query one up-stream host in order to maximize caching
|
||||
|
@ -199,7 +202,7 @@ autokill=yes
|
|||
; precache - Utilize/Permit precaching with this peer (to pre
|
||||
; cache means to provide an answer when no request
|
||||
; was made and is used so that machines with few
|
||||
; routes can push those routes up a to a higher level).
|
||||
; routes can push those routes up to a higher level).
|
||||
; outgoing means we send precache routes to this peer,
|
||||
; incoming means we permit this peer to send us
|
||||
; precache routes. symmetric means we do both.
|
||||
|
@ -208,6 +211,12 @@ autokill=yes
|
|||
; precache, nor can you mix symmetric/inbound model with symmetric/outbound
|
||||
; precache.
|
||||
;
|
||||
; qualify - Enable qualifying the peer to determine reachable status.
|
||||
; Set to yes, no, or number of milliseconds for qualifying
|
||||
; the peer's reachable status.
|
||||
;
|
||||
; register - Enable registering with the peer. This presupposes that the
|
||||
; peer's host option for us is dynamic. (yes/no value)
|
||||
;
|
||||
; The '*' peer is special and matches an unspecified entity
|
||||
;
|
||||
|
|
|
@ -8,26 +8,26 @@
|
|||
autoload=yes
|
||||
;
|
||||
; Any modules that need to be loaded before the Asterisk core has been
|
||||
; initialized (just after the logger has been initialized) can be loaded
|
||||
; using 'preload'. This will frequently be needed if you wish to map all
|
||||
; module configuration files into Realtime storage, since the Realtime
|
||||
; driver will need to be loaded before the modules using those configuration
|
||||
; files are initialized.
|
||||
; initialized (just after the logger initialization) can be loaded
|
||||
; using 'preload'. 'preload' forces a module and the modules it
|
||||
; is known to depend upon to be loaded earlier than they normally get
|
||||
; loaded.
|
||||
;
|
||||
; An example of loading ODBC support would be:
|
||||
;preload => res_odbc.so
|
||||
;preload => res_config_odbc.so
|
||||
; NOTE: There is no good reason left to use 'preload' anymore. It was
|
||||
; historically required to preload realtime driver modules so you could
|
||||
; map Asterisk core configuration files to Realtime storage.
|
||||
; This is no longer needed.
|
||||
;
|
||||
; Uncomment the following if you wish to use the Speech Recognition API
|
||||
;preload => res_speech.so
|
||||
;preload => your_special_module.so
|
||||
;
|
||||
; If you want Asterisk to fail if a module does not load, then use
|
||||
; the "require" keyword. Asterisk will exit with a status code of 2
|
||||
; if a required module does not load.
|
||||
;
|
||||
; require = chan_sip.so
|
||||
; require = chan_pjsip.so
|
||||
;
|
||||
; If you want you can combine with preload
|
||||
; preload-require = res_odbc.so
|
||||
; preload-require = your_special_module.so
|
||||
;
|
||||
;load => res_musiconhold.so
|
||||
;
|
||||
|
@ -37,4 +37,8 @@ autoload=yes
|
|||
noload => chan_alsa.so
|
||||
;noload => chan_oss.so
|
||||
noload => chan_console.so
|
||||
|
||||
noload => res_hep.so
|
||||
noload => res_hep_pjsip.so
|
||||
noload => res_hep_rtcp.so
|
||||
;
|
||||
|
|
|
@ -288,8 +288,8 @@
|
|||
; a transport that you'll need to uncomment from the previous examples.
|
||||
;
|
||||
; Uncomment one of the transport lines to choose which transport you want. If
|
||||
; not specified then the default transport chosen is the first defined transport
|
||||
; in the configuration file.
|
||||
; not specified then the default transport chosen is the first compatible transport
|
||||
; in the configuration file for the contact URL.
|
||||
;
|
||||
; Modify the "max_contacts=" line to change how many unique registrations to allow.
|
||||
;
|
||||
|
@ -608,6 +608,10 @@
|
|||
;direct_media_glare_mitigation=none ; Mitigation of direct media re INVITE
|
||||
; glare (default: "none")
|
||||
;direct_media_method=invite ; Direct Media method type (default: "invite")
|
||||
;trust_connected_line=yes ; Accept Connected Line updates from this endpoint
|
||||
; (default: "yes")
|
||||
;send_connected_line=yes ; Send Connected Line updates to this endpoint
|
||||
; (default: "yes")
|
||||
;connected_line_method=invite ; Connected line method type.
|
||||
; When set to "invite", check the remote's
|
||||
; Allow header and if UPDATE is allowed, send
|
||||
|
@ -670,7 +674,12 @@
|
|||
;timers=yes ; Session timers for SIP packets (default: "yes")
|
||||
;timers_sess_expires=1800 ; Maximum session timer expiration period
|
||||
; (default: "1800")
|
||||
;transport= ; Desired transport configuration (default: "")
|
||||
;transport= ; Explicit transport configuration to use (default: "")
|
||||
; This will force the endpoint to use the specified transport
|
||||
; configuration to send SIP messages. You need to already know
|
||||
; what kind of transport (UDP/TCP/IPv4/etc) the endpoint device
|
||||
; will use.
|
||||
|
||||
;trust_id_inbound=no ; Accept identification information received from this
|
||||
; endpoint (default: "no")
|
||||
;trust_id_outbound=no ; Send private identification details to the endpoint
|
||||
|
@ -830,13 +839,22 @@
|
|||
; This option must also be enabled in the system
|
||||
; section.
|
||||
; (default: no)
|
||||
suppress_q850_reason_headers =
|
||||
;suppress_q850_reason_headers =
|
||||
; Suppress Q.850 Reason headers for this endpoint.
|
||||
; Some devices can't accept multiple Reason headers
|
||||
; and get confused when both 'SIP' and 'Q.850' Reason
|
||||
; headers are received. This option allows the
|
||||
; 'Q.850' Reason header to be suppressed.
|
||||
; (default: no)
|
||||
;ignore_183_without_sdp =
|
||||
; Do not forward 183 when it doesn't contain SDP.
|
||||
; Certain SS7 internetworking scenarios can result in
|
||||
; a 183 to be generated for reasons other than early
|
||||
; media. Forwarding this 183 can cause loss of
|
||||
; ringback tone. This flag emulates the behavior of
|
||||
; chan_sip and prevents these 183 responses from
|
||||
; being forwarded.
|
||||
; (default: no)
|
||||
|
||||
;==========================AUTH SECTION OPTIONS=========================
|
||||
;[auth]
|
||||
|
@ -1124,6 +1142,27 @@ suppress_q850_reason_headers =
|
|||
; from incoming SIP URI user fields are always truncated at the
|
||||
; first semicolon.
|
||||
|
||||
;send_contact_status_on_update_registration=no ; Enable sending AMI ContactStatus
|
||||
; event when a device refreshes its registration
|
||||
; (default: "no")
|
||||
|
||||
;taskprocessor_overload_trigger=global
|
||||
; Set the trigger the distributor will use to detect
|
||||
; taskprocessor overloads. When triggered, the distributor
|
||||
; will not accept any new requests until the overload has
|
||||
; cleared.
|
||||
; "global": (default) Any taskprocessor overload will trigger.
|
||||
; "pjsip_only": Only pjsip taskprocessor overloads will trigger.
|
||||
; "none": No overload detection will be performed.
|
||||
; WARNING: The "none" and "pjsip_only" options should be used
|
||||
; with extreme caution and only to mitigate specific issues.
|
||||
; Under certain conditions they could make things worse.
|
||||
|
||||
;norefersub=yes ; Enable sending norefersub option tag in Supported header to advertise
|
||||
; that the User Agent is capable of accepting a REFER request with
|
||||
; creating an implicit subscription (see RFC 4488).
|
||||
; (default: "yes")
|
||||
|
||||
; MODULE PROVIDING BELOW SECTION(S): res_pjsip_acl
|
||||
;==========================ACL SECTION OPTIONS=========================
|
||||
;[acl]
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
; If you want to see more detail please check the documentation sources
|
||||
; mentioned at the top of this file.
|
||||
|
||||
; ============================================================================
|
||||
; NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
|
||||
;
|
||||
; This file does not maintain the complete option documentation.
|
||||
; ============================================================================
|
||||
|
||||
; Documentation
|
||||
;
|
||||
; The official documentation is at http://wiki.asterisk.org
|
||||
|
@ -99,8 +105,6 @@
|
|||
; If an aor/contact or match/identify is explicitly supplied,
|
||||
; remote_hosts will not be used to automatically create contacts
|
||||
; or matches respectively.
|
||||
; Hostnames must resolve to A, AAAA or CNAME records.
|
||||
; SRV records are not currently supported.
|
||||
; (default: "")
|
||||
|
||||
;outbound_proxy= ; Setting this is a shortcut for setting
|
||||
|
|
|
@ -65,6 +65,20 @@ pre-connect => yes
|
|||
; information before we attempt another connection? This increases
|
||||
; responsiveness, when a database resource is not working.
|
||||
;negative_connection_cache => 300
|
||||
;
|
||||
; Enable query logging. This keeps track of the number of prepared queries
|
||||
; and executed queries as well as the query that has taken the longest to
|
||||
; execute. This can be useful for determining the latency with a database.
|
||||
; The data can be viewed using the "odbc show" CLI command.
|
||||
; Note that only successful queries are logged currently.
|
||||
;logging => yes
|
||||
;
|
||||
; Slow query limit. If a query exceeds the given amount of time (in milliseconds)
|
||||
; when executing then a WARNING message will be output to indicate that there
|
||||
; may be a problem. Note that logging must be set to "yes" for this to occur. By
|
||||
; default this is set to 5000 milliseconds (or 5 seconds). If you would like to
|
||||
; disable the WARNING message it can be set to "0".
|
||||
;slow_query_limit => 5000
|
||||
|
||||
[mysql2]
|
||||
enabled => no
|
||||
|
|
|
@ -102,7 +102,7 @@ context => parkedcalls ; Which context parked calls and the default par
|
|||
; Dial() to 'SIP/0004F2040001'.
|
||||
;
|
||||
; During the timeout procedure, the following variables are set
|
||||
; PARKINGSLOT - extension that the call was parked in prior to timing out
|
||||
; PARKING_SPACE - extension that the call was parked in prior to timing out
|
||||
; PARKEDLOT - name of the lot that the call was parked in prior to timing out
|
||||
; PARKER - dial string to call the device that parked the call
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ rtpend=20000
|
|||
; seconds after starting learning mode. Once learning mode completes the
|
||||
; current stream is locked in and cannot change until the next
|
||||
; renegotiation.
|
||||
; Valid options are "no" to disable strictrtp, "yes" to enable strictrtp,
|
||||
; and "seqno", which does the same thing as strictrtp=yes, but only checks
|
||||
; to make sure the sequence number is correct rather than checking the time
|
||||
; interval as well.
|
||||
; This option is enabled by default.
|
||||
; strictrtp=yes
|
||||
;
|
||||
|
@ -98,6 +102,10 @@ rtpend=20000
|
|||
;
|
||||
; ice_blacklist =
|
||||
;
|
||||
; The MTU to use for DTLS packet fragmentation. This option is set to 1200
|
||||
; by default. The minimum MTU is 256.
|
||||
; dtls_mtu = 1200
|
||||
;
|
||||
[ice_host_candidates]
|
||||
;
|
||||
; When Asterisk is behind a static one-to-one NAT and ICE is in use, ICE will
|
||||
|
@ -114,13 +122,19 @@ rtpend=20000
|
|||
;
|
||||
; The format for these overrides is:
|
||||
;
|
||||
; <local address> => <advertised address>
|
||||
; <local address> => <advertised address>,[include_local_address]
|
||||
;
|
||||
; The following will replace 192.168.1.10 with 1.2.3.4 during ICE
|
||||
; negotiation:
|
||||
;
|
||||
;192.168.1.10 => 1.2.3.4
|
||||
;
|
||||
; The following will include BOTH 192.168.1.10 and 1.2.3.4 during ICE
|
||||
; negotiation instead of replacing 192.168.1.10. This can make it easier
|
||||
; to serve both local and remote clients.
|
||||
;
|
||||
;192.168.1.10 => 1.2.3.4,include_local_address
|
||||
;
|
||||
; You can define an override for more than 1 interface if you have a multihomed
|
||||
; server. Any local interface that is not matched will be passed through
|
||||
; unaltered. Both IPv4 and IPv6 addresses are supported.
|
||||
|
|
|
@ -73,6 +73,10 @@ maxlogins=3
|
|||
;
|
||||
;userscontext=default
|
||||
;
|
||||
; Aliases allow a mailbox to be referenced by an alias. The aliases are
|
||||
; specified in the special context named here. There is no default.
|
||||
;aliasescontext=myaliases
|
||||
;
|
||||
; If you need to have an external program, i.e. /usr/bin/myapp
|
||||
; called when a voicemail is left, delivered, or your voicemailbox
|
||||
; is checked, uncomment this.
|
||||
|
@ -233,7 +237,6 @@ pagerdateformat=%A, %B %d, %Y at %r
|
|||
; Default: no
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
;
|
||||
|
||||
; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options>
|
||||
; If email is specified, a message will be sent when a voicemail is received, to
|
||||
|
@ -451,6 +454,13 @@ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM
|
|||
;4110 => 3443,Rob Flynn,rflynn@blueridge.net
|
||||
;4235 => 1234,Jim Holmes,jim@astricon.ips,,Tz=european
|
||||
|
||||
;
|
||||
; Aliases allow alternate references to mailboxes. See the "aliasescontext"
|
||||
; parameter in the "general" section.
|
||||
;
|
||||
[myaliases]
|
||||
1234@devices => 1234@default
|
||||
;6200@devices => 4200@default
|
||||
|
||||
;
|
||||
; Mailboxes may be organized into multiple contexts for
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue