From 7418128b0df1693231e260e3e95155e3d28f540f Mon Sep 17 00:00:00 2001 From: George Joseph Date: Wed, 3 Sep 2025 06:40:36 -0600 Subject: [PATCH 1/5] Rework the contribution guide and style guide. * The docs/Asterisk-Community/Wiki-Organization-and-Style-Guide.md file has been deleted. * A new file docs/Contributing-to-the-Documentation.md has been added that contains extensive instructions/guidelines for content creation and building and testing the website locally. * The README.md file now just contains a link to the new page on the live website. * The Makefile was tweaked to be a bit friendlier. * requirements.txt was updated to the latest versions of the python packages. * mkdocs.yml was updated to enable Mermaid diagrams --- Makefile | 15 +- README.md | 226 +------ docs/.pages | 2 +- .../Wiki-Organization-and-Style-Guide.md | 161 ----- docs/Contributing-to-the-Documentation.md | 628 ++++++++++++++++++ mkdocs.yml | 6 +- requirements.txt | 7 +- 7 files changed, 650 insertions(+), 395 deletions(-) delete mode 100644 docs/Asterisk-Community/Wiki-Organization-and-Style-Guide.md create mode 100644 docs/Contributing-to-the-Documentation.md diff --git a/Makefile b/Makefile index 8a4fe3ca60..22eb82cc75 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # # NOTE: For readability, two space characters are used to # indent the contents of make ifeq/ifneq statements. -# Don;y confuse these with tabs used to indent rule +# Don't confuse these with tabs used to indent rule # recipies. # @@ -10,10 +10,17 @@ DEPLOY_BRANCH ?= gh-pages BUILD_DIR ?= ./temp GH=gh JOB_DATE ?= $(shell date +%F) +SERVE_OPTS ?= -a [::]:8000 +BRANCHES ?= +BRANCH ?= -include Makefile.inc -ifneq ($(BRANCH),) - -include Makefile.$(BRANCH).inc +-include Makefile.inc + +ifneq ($(BRANCHES),) + COMMA := , + BB := $(subst $(COMMA), ,$(BRANCHES)) + includes := $(foreach b,$(BB),Makefile.$(b).inc) + -include $(includes) endif # 'make' has a realpath function but it only works on diff --git a/README.md b/README.md index ffe7fb2e8f..c38de1ca09 100644 --- a/README.md +++ b/README.md @@ -1,228 +1,8 @@ # Description -This repository contains the Asterisk Documentation project. +This repository contains the documentation for the [Asterisk](https://github.com/asterisk/asterisk) project. -# Recent Changes +## Recent Changes -The packages used to create the documentation were upgraded on February 2 2024. While there are no breaking changes, some new capabilities were added that, if used going forward, won't render correctly with the older versions. So, if you build documentation locally, you should delete your local virtualenv and re-create it using the new requirements.txt file. The new features will be documented separately. +The instructions formerly in this page for contributing to this repository have moved to the [Contributing to the Documentation](https://docs.asterisk.org/Contributing-to-the-Documentation) page on the live website. -# Static Documentation - -The static documentation contained in the ./docs/ directory is written directly in markdown. The publish process uses [mkdocs](https://www.mkdocs.org) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) to generate the HTML web site. The directory structure is fairly straightforward so if you wish to contribute, you should fork this repository and submit pull requests against files in that directory. - -All contributions are subject to the -[Creative Commons Attribution-ShareAlike 3.0 United States](LICENSE.md) license. - -## Markdown Flavor -The docs are written in standard markdown, not GitHub Flavored markdown. There are lots of extensions available though. Most of the extensions provided by [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/) are enabled except those only available to paying sponsors and a few that don't make sense in this environment. - -> [!NOTE] -> The conversion process that moved the documentation from the Confluence Wiki used equals signs `=====` and dashes `----` to denote headers. The new infrastructure renders those correctly but they do not get added to the page's table of contents. Going forward, you should always use hash signs `#`, `##`, `###`, etc to denote headers. - -### PyMdown Extensions - -Many extensions from the [PyMdown](https://facelessuser.github.io/pymdown-extensions/) plugin are also available. The `admonition` extension is particularly useful as a replacement for the legacy `!!! note` admonition style because it uses a trailer to mark the end of the admonition instead of just a blank line. This allows you to add things like code blocks and quotes inside admonitions. - -Admonition Example: - -``` -/// warning | Don't Do This -Don't do this in your code!!! -''' - free(NULL); -''' -/// -``` - -You couldn't do that with the legacy `!!!` style admonition. - -If you decide to use any of the extensions from this plugin (and you should use them where possible), don't use the legacy version in the same page. For instance, don't mix `///` admonitions with `!!!` admonitions in the same page. There's a good chance they won't render correctly. - -At some point, we'll try and convert all of the existing legacy admonitions to the new style. - -[PyMdown Documentation](https://facelessuser.github.io/pymdown-extensions/extensions/arithmatex/) - -Enabled extensions: - -``` -betterem -blocks.admonition -blocks.definition -caret -critic -details -emoji -highlight -inlinehilite -keys -mark -saneheaders -smartsymbols -snippets -superfences -tabbed -tilde -``` - -See `markdown_extensions` in the [mkdocs.yml](mkdocs.yml) file for the current list. - -# Dynamic Documentation - -The dynamic documentation includes the pages generated from Asterisk itself and includes: -* AGI_Commands -* AMI_Actions -* AMI_Events -* Asterisk_REST_Interface -* Dialplan_Applications -* Dialplan_Functions -* Module_Configuration - -The publish process gets this information directly from the Asterisk CreateDocs job (which runs nightly) and generates markdown. For this reason, all changes to the dynamic documentation need to be made in the Asterisk source code itself. - -The AGI, AMI, Dialplan and Module documentation comes from the documentation embedded in the provider modules and generated by CreateDocs running `xmldoc dump` from the Asterisk CLI. You can also use a core-en_US.xml or full-en_US.xml file generated from a local asterisk build. See below for more information. - -The Asterisk_REST_Interface documentation comes from the markdown files generated by CreateDocs running `make ari-stubs`. You can also use locally generated markdown files. See below for more information. - -# Build/Test Dependencies - -Dependencies for documentation can be installed using the included requirements.txt file. - -``` -$ pip3 install -r requirements.txt -``` - -If you don't want to install the requirements for the current user or globally, you can create a virtual environment specific to this directory first... - -``` -$ python -m venv ./.venv -$ source .venv/bin/activate -(.venv)$ pip3 install -r requirements.txt -# run `deactivate` when done -(.venv)$ deactivate -$ -``` - -The next time you want to test, you can just activate the virtual environment without needing to install the dependencies again. The `.venv` directory is already in the `.gitignore` file. - -You'll also need the [`gh`](https://cli.github.com) tool to pull down the dynamic documentation from the CreateDocs job. - -> [!NOTE] -> The documentation build process no longer uses the `mike` python package. - -# Building and Testing the Documentation - -## Prepare - -Everything is done from the [`documentation`](https://github.com/asterisk/documentation) repository so, if you haven't already, clone it and check out the `main` branch. - -``` -$ git clone -b main https://github.com/asterisk/documentation -$ cd documentation -``` - -Create a `Makefile.inc` file with some configuration variables. This file must **not** be checked in. Here are the contents to use: - -``` -# BUILD_DIR := # Defaults to ./temp - -# MkDocs needs to know the base URL for the documentation site -# to properly handle links and navigation. -# If you're going to deploy the site locally, use the -# URL of your local server. -# The default is https://docs.asterisk.org which is -# probably not what you want. -# NOTE: You MUST use the export keyword for this variable. -# export SITE_URL := - -# The following 2 DEPLOY_ variables are only needed if you -# need to deploy the built site to some other repo. -# The nightly job uses this to publish the site to -# GitHub pages. -# DEPLOY_REMOTE := -# DEPLOY_BRANCH := # Defaults to gh-pages - -# The comma-separated list of branches for which dynamic -# documentation should be built when doing a `make` without -# specifying BRANCH=. -# BRANCHES := 20,21,22 - -# If you don't want to build the static documentation at all... -# NO_STATIC=yes - -# If you don't want the resulting HTML minified, set NO_MINIFY. -# Minification can reduce the space required to host the full -# site by about 30% but it does take over double the time to -# generate the site. -# NO_MINIFY=yes - -# If you want to serve the resulting site with mkdocs serve, -# you can specify any additional options to pass to it here: -# SERVE_OPTS := -a [::]:8000 -``` - -If you're planning on using local sources for the dynamic Asterisk documentation, you'll *also* need to create a `Makefile..inc` file *for each branch*. - -``` -# If you want to use a local XML file to generate the -# AGI, AMI, Dialplan and Module_Configuration documentation, -# specify it here. -# ASTERISK_XML_FILE := /asterisk/doc/core-en_US.xml -# -# If you want to use local markdown files for the ARI -# documentation, specify a path to a directory containing -# the markdown generated by "make ari-stubs". -# ASTERISK_ARI_DIR := /asterisk/doc/rest-api -# -# If you want to use local XML but skip processing ARI -# altogether, set this variable to "yes". -# SKIP_ARI := yes - -# If either ASTERISK_XML_FILE or ASTERISK_ARI_DIR are not set, -# that documentation source will be downloaded from the -# CreateDocs job. -``` - -## Build and Deploy - -### To build the entire site: - -``` -$ make -``` - -This will build the static pages and the dynamic pages for all branches listed in the `BRANCHES` variable. The fully functioning site will be created at `$(BUILD_DIR)/site`. You can serve that directory with `make serve`, which runs `mkdocs serve` or a web server of your own choosing. `mkdocs serve` rebuilds the entire site when it starts so you may want to use a standard web server if you plan on doing this a lot. If you do use `make serve`, you can use the `SERVE_OPTS` variable in Makefile.inc to add additional options to the `mkdocs serve` command line. - -### To build just the static pages - -``` -$ make BRANCHES= -``` - -### To build just 2 branches - -Building branches does need at least a skeleton static layout so `static-setup` will be built first if it hasn't already been built. - -``` -$ make BRANCHES=18,20 -``` - -If you only want the skeleton static documentation, you can add `NO_STATIC=yes` to that command line... - -``` -$ make BRANCHES=18,20 NO_STATIC=yes -``` - -### To build just 1 branch - -If you're always going to build just 1 branch's dynamic documentation, you can skip the `Makefile..inc` file and just place everything in the main `Makefile.inc`: - -Makefile.inc: - -``` -ASTERISK_XML_FILE := /core-en_US.xml -ASTERISK_ARI_DIR := /rest-api -BRANCHES := 20 -NO_STATIC := yes -``` - -And just run `make`. diff --git a/docs/.pages b/docs/.pages index 0aec594938..40f75d1170 100644 --- a/docs/.pages +++ b/docs/.pages @@ -19,4 +19,4 @@ nav: - Certified-Asterisk_20.7_Documentation - Test-Suite-Documentation - Historical-Documentation - + - Contributing-to-the-Documentation.md diff --git a/docs/Asterisk-Community/Wiki-Organization-and-Style-Guide.md b/docs/Asterisk-Community/Wiki-Organization-and-Style-Guide.md deleted file mode 100644 index aec71c2e34..0000000000 --- a/docs/Asterisk-Community/Wiki-Organization-and-Style-Guide.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: Wiki Organization and Style Guide -pageid: 28315986 ---- - -Overview -======== - -!!! warning -# This page is now obsolete. Revisions in progress. - -This page should serve as a guide for creating organized, consistent, easy to consume content on the Asterisk wiki. It covers organization, content design and formatting. - -You can find research all over the web on why these goals are important. Here's a link to [Nielson Norman Group on How Users Read on the Web](http://www.nngroup.com/articles/how-users-read-on-the-web/) - -Organization of Pages -===================== - -Spaces, parent and child pages ------------------------------- - -All Asterisk documentation pages are contained within the Asterisk space. Most of those editing on wiki.asterisk.org will only have edit permissions within the Asterisk space. - -Within the Asterisk space there are many top-level parent pages available. We've included some info about each below to help you decide where a page goes. - -* [About the Project](/About-the-Project) - Any general information about the project. Licensing, History, What is Asterisk? -* [Getting Started](/Getting-Started) - Information relevant to completely new users, information on installation and how to get rolling into configuration and the rest of the documentation. -* [Operation](/Operation) - Details concerning Asterisk's operation. That is, starting and stopping the Asterisk daemon, command line operation and other non-configuration tasks. -* [Fundamentals](/Fundamentals) - Basic, key and core concepts of Asterisk. Some of the most important foundational things to know about Asterisk. -* [Configuration](/Configuration) - How everything is configured. Where are the files? How do I use them? How do I program dialplan? How do I use the APIs? -* [Deployment](/Deployment) - Examples, tutorials, how-tos and recommendations for specific use-cases or scenarios of deployment. How do I deal with Asterisk in a NATed environment? How do I build a simple PBX? -* [Development](/Development) - All information regarding the development of Asterisk itself. -* [Asterisk Test Suite Documentation](/Test-Suite-Documentation) - Documentation for the test suite! Primarily for developers. -* [Asterisk Security Vulnerabilities](/About-the-Project/Asterisk-Security-Vulnerabilities) - How the project handles security vulnerabilities. -* [Asterisk Community](/Asterisk-Community) - Anything falling under community. The places we meet, our code of conduct, community services. - -Plus there are a few sections titled "Asterisk X Documentation" where X is the version. These sections are reserved for command reference content, mostly pushed to the wiki via scripts that pull from the source documentation. - -!!! note - Pages created or modified by "wikibot" are generated by scripts. - -[//]: # (end-note) - -On this Page - -Considerations before creating new content ------------------------------------------- - -Find out if a new page is really needed. Check the following: - -* Have you searched the Asterisk space to see if it exists already? -* Is there already *some* content that you could use to build on? -* Is there related content which should be consolidated with your new content? - -If obsolete related content exists and you decide to delete, rename or move it, then check the following: - -* [check for inbound links](https://confluence.atlassian.com/display/DOC/Viewing+Page+Information). If there are many referrers from external sources, you should ask the Asterisk project manager and others before renaming or deleting that page. -* If there are inbound links from wiki.asterisk.org pages, then we can of course go update those. For links from external sources, we have to decide how much we value breaking or not breaking those links. - -Will the content fill more than a single screen-worth of space? If so, then you probably want to split it into multiple pages, or one page with sub-pages. When linking on a forum or mailing list, this makes it easier to link to specific chunks of content with shorter URLs. - -Use the General Asterisk Wiki Page template for creating a new page with a very basic outline. It should include the Table of Contents macro discussed later on. The template is listed in the templates dialog when creating a new page. - -Content Design -============== - -Design the content for a particular audience --------------------------------------------- - -**Consider the audience** for the content you are writing. A good clue is the section of the wiki you are placing the article in. - -For example, pages in the Getting Started section should be oriented towards a completely new Asterisk user. That means the content should have a very narrow focus, making sure to explain concepts discussed and if a tutorial, provide small manageable chunks of tasks. - -While it is acceptable to add content for very experienced Asterisk users, on the other end of the scale we do want to limit ourselves. Though Asterisk runs on Linux, the purpose of this wiki is not to teach Linux fundamentals. Pages in the Getting Started section do set the expectation that you should be familiar with Linux to use Asterisk. - -**Set expectations**. In a section like Deployment, which could contain content for new users or experienced administrators, you should state requirements or experience at the beginning of the content. - -Style based on purpose of content ---------------------------------- - -As the heading says, the purpose of your content should determine what style you craft it in. - -* **Explanatory or Descriptive** - These styles are useful for reference material. Pages describing configuration sections, (as opposed to how-to configure) and feature or functionality descriptions all should be written in these styles. -* **Procedural** - Configuration how-to, tutorials, examples and guides often include this style which often features lots of bulleted lists and step by step instructions. -* **Frequently Asked Questions** - Often a FAQ appears as a list of questions with their answers. Only use this style when there is no other better way to do it. You could format a lot of content this way, but it doesn't make sense most of the time. - -Grammar, Punctuation, Spelling ------------------------------- - -The Ubuntu documentation team has a good guide for [grammar, punctuation and spelling](https://wiki.ubuntu.com/DocumentationTeam/StyleGuide/SpellingPunctuationGrammar). Other than those rules, follow typical English language and writing conventions. It is always a good idea to have at least one or two other editors review your content for obvious problems. - -Content Formatting and Markup -============================= - -Naming a page -------------- - -Page names should be concise. i.e., The simplest summary of the content within it or under it. That means taking into consideration sub-pages if the page in question is a top-level parent page. - -Page names should be written in [Title Case](http://www.grammar-monster.com/lessons/capital_letters_title_case.htm). - -The page name will be included in the URL the wiki generates, so try to avoid any special characters or symbols and keep it as short as possible. - -Headings --------- - -Good use of headings allows a reader to quickly break-down the content on the page to find what they need. Each heading should be a concise summary of the content under that heading. - -Most pages won't use more than two or three levels of headings. h1 for sections, h2 for sub-sections, and h3 if you really need to break those sub-sections down further. If you find yourself getting into a lot of h3 or h4 headings, consider creating sub-pages rather than including so much nested content on a single page. - -Use [Title Case](http://www.grammar-monster.com/lessons/capital_letters_title_case.htm) for h1 headings. For lower headings use only sentence case; that is, only use capitalization how you would in a typical sentence. - -Linking -------- - -As you review content that you have written, try to link words to other content relevant to what you are discussing. Especially if it would help the user understand that topic. - -There are a variety of ways to link to other pages and content. All of them are described in the confluence documentation, in [Working with Links](https://confluence.atlassian.com/display/CONF55/Working+with+Links). - -When linking from an external site, outside Confluence, it is important to use a permalink. Here is an excerpt from the Confluence documentation: - -The best way to link to a Confluence page from outside Confluence, for example on a website or in an email message, is to use the tiny link which is a permanent URL. This ensures that the link to the page is not broken if the page name changes. - -To access the permanent URL for a page: - -1. View the page you wish to link to. -2. Choose **Tools** > **Link to this page**. -3. Copy the **Tiny Link**. -4. Use the tiny link in your website or email message. - -You do not need to use the tiny link to link to pages within your Confluence site. Confluence automatically updates links when you rename or move a page to another space. - -Common macros -------------- - -Confluence provides a variety of macros serving all sorts of functions. The confluence documentation on [Working with Macros](https://confluence.atlassian.com/display/DOC/Working+with+Macros) is very helpful to understand their usage. Below we'll list some macros that are commonly used with notes on how to use them specific to the Asterisk wiki. - -### Macro - Table of Contents - -The TOC macro should be put at the top right-hand side of the page. - -To make sure it aligns correctly you need to place a section macro, then two column macros inside the section. After that put a panel macro inside the second column and finally the TOC goes inside the panel. You can then edit the panel title to say something like "On this Page". For an example you can edit this page itself. Look at the very top and see how the TOC is laid out inside the the other macros. - -Always set the TOC maxlevel to 2, as it is generally not necessary for a page-level TOC to have more detail. - -### Macro - No Format - -Often when pasting text from an Asterisk log or the CLI you can run into issues as characters may be interpreted by the WYSIWYG editor as markup. Use the No Format macro to include a block of text to which no formatting will be applied. - -### Macro - Expand - -This macro gives you a click-able link where upon being clicked provides a slide-out panel of content. Use this when you need to fit many large chunks of example code or terminal output into a small section. It'll prevent the code from taking up all the screen real-estate and then requiring the user to scroll through it all. - -### Macro - Warning, Info, Note, Tip - -Try to avoid using these call-out boxes too often as they can be visually distracting and a few too many can make a page noisy. They are most useful with sparing application. - -* Info - Most tame visually. Use this when you want to call-out a specific, brief piece of info that isn't necessarily critical, but could be very helpful. -* Note - A bright yellow exclamation sign. Maybe you want to share a word of caution or advise about requirements. "This example only works with a feature added in 11.1.1!" -* Tip - A bright green check mark. Useful when you want to mention shortcuts to a process already described detail, or call out brief command-line trick related to your content. -* Warning - This is bright red and very eye-catching. Use when you need to call out a piece of information very critical that could cause major problems for the user if not read or understood. diff --git a/docs/Contributing-to-the-Documentation.md b/docs/Contributing-to-the-Documentation.md new file mode 100644 index 0000000000..f7be514b71 --- /dev/null +++ b/docs/Contributing-to-the-Documentation.md @@ -0,0 +1,628 @@ + +# Contributing to the Documentation + +## How to Make Changes + +The source for this documentation website is hosted in the [Asterisk Documentation](https://github.com/asterisk/documentation) GitHub repository. To make changes, follow these basic steps... + +* Fork the repository into your own GitHub account. +* Clone your fork to your local development environment. +* Make changes to the markup documents in the ./docs folder. +* Build the site locally and review your changes. +* Commit your changes. +* Push your changes to your fork. +* Create a pull request. + +## Get the repository + +All changes need to go through the GitHub Pull Request process. To make this easier, you should install the [GitHub CLI "gh"](https://cli.github.com) tool. Most distributions have it available as the "gh" package. Once the tool is installed, fork and clone the asterisk/documentation repo. Since "documentation" is a common name, you'll probably want to name your fork "asterisk-documentation". + +```sh +$ gh repo fork asterisk/documentation --default-branch-only --fork-name asterisk-documentation --clone +... +$ cd asterisk-documentation +$ git remote -v +origin https://github.com//asterisk-documentation.git (fetch) +origin https://github.com//asterisk-documentation.git (push) +upstream https://github.com/asterisk/documentation.git (fetch) +upstream https://github.com/asterisk/documentation.git (push) +``` + +When everything finishes, create a new branch from the `main` branch in which to do your work. Never do your work in the `main` branch itself! + +```sh +$ git checkout -b main-my-work +``` + +You're ready to go! + +## Site Organization + +* [About the Project](/About-the-Project) - Any general information about the project. Licensing, History, What is Asterisk? +* [Asterisk Community](/Asterisk-Community) - Anything falling under community. The places we meet, our code of conduct, community services. +* [Fundamentals](/Fundamentals) - Basic, key and core concepts of Asterisk. Some of the most important foundational things to know about Asterisk. +* [Getting Started](/Getting-Started) - Information relevant to completely new users, information on installation and how to get rolling into configuration and the rest of the documentation. +* [Configuration](/Configuration) - How everything is configured. Where are the files? How do I use them? How do I program dialplan? How do I use the APIs? +* [Deployment](/Deployment) - Examples, tutorials, how-tos and recommendations for specific use-cases or scenarios of deployment. How do I deal with Asterisk in a NATed environment? How do I build a simple PBX? +* [Operation](/Operation) - Details concerning Asterisk's operation. That is, starting and stopping the Asterisk daemon, command line operation and other non-configuration tasks. +* [Development](/Development) - All information regarding the development of Asterisk itself. +* [Latest API](/Latest_API) - The auto-generated API documentation for the latest Asterisk release. +* Asterisk XX Documentation - The auto-generated API documentation for all current Asterisk releases. Changes to these pages MUST be done in the Asterisk source file that they were generated from. See [Dynamic Documentation](#dynamic-documentation) below. +* [Asterisk Test Suite Documentation](/Test-Suite-Documentation) - Documentation for the test suite! Primarily for developers. +* [Historical Documentation](/Historical-Documentation) - Documentation that is no longer current but kept for historical purposes.for the test suite! Primarily for developers. + +Each section and sub-section resides in its own directory under the `./docs/` directory in the repository. + +Do NOT create new top-level pages/sections without consulting with the Asterisk development team first. + +## Page/Section Operations + +### Adding a new page + +First, determine if a new page is really needed. + +* Have you searched the website to see if it exists already? +* Is there already *some* content that you could use to build on? +* Is there related content which should be consolidated with your new content? + +/// warning +Directory and file names are used to create the left sidebar on the rendered site and become the URL for that content. Take this into account when naming new content! +/// + +A single new page must be named using Title Case with spaces replaced by dashes and must have an `.md` file suffix. Example: `My-New-Page.md`. Only characters in the set `[A-Za-z0-9_.-]` are allowed. By default the page title in the left sidebar is derived from the file name with the dashes converted to spaces and the `.md` suffix removed. The file should be placed in the directory for the section or sub-section it belongs to. For example: + +``` +documentation/ + docs/ + Configuration/ + My-New-Page.md +``` + +If you anticipate adding supporting images or other artifacts, create a directory with the name of your page and place the content in a file named `index.md` in that directory. You can then place your supporting artifacts next to the `index.md` file. For example: + +``` +documentation + docs/ + Configuration/ + My-New-Page/ + index.md + image1.png + image2.png +``` + +When rendered, the index will only show "My New Page" under "Configuration" and when clicked on, will automatically display the contents of `index.md`. + +### Adding a new section + +Adding a new section is as simple as adding a new directory to the repo filesystem. The same naming rules apply as for pages with the exception of adding the `.md` suffix. You should also add an `index.md` page that describes describe the section. You can then add your additional pages as above. + +### Page ordering + +The default page ordering in the left sidebar will be as it is ordered in the filesystem. If you want to customize the ordering for a section, add a `.pages` YAML file to the section's directory that lists the directory contents in the order it should be displayed on the rendered website. For example: + +```yaml title="Sample .pages file" +nav: + - Page-1.md + - Section-2 + - Page-3.md +``` + +Each entry must be a name as it appears in the filesystem. Only list what you want to appear in the left sidebar. Don't list supporting files like images and don't list `index.md` files. + +### Deleting, renaming or moving pages or sections + +If you delete, rename or move pages or sections, any links to those pages will return a 404 "Not found". That's usually not a good idea. If you are deleting old content, move that page to the Historical Documentation section and create a [redirect](#redirects) for that page. If you are replacing with updated content or renaming a page, you don't need to move the original to Historical Documentation but you do need to create a redirect. See [Redirects](#redirects) below. + +You'll also need to search the full docs directory for any internal links to the moved content and update them accordingly. You could use something like `grep -r --include='*.md' "Moved_Page"` to search. + +### Redirects + +If you've moved a page, you should create a redirect for it so any links from outside to the original location will still work. Redirects are listed in the top-level `mkdocs.yml` file in the `plugins.redirects.redirect_maps` section. Follow the same pattern as the existing entries. + +Redirects should also be used to fix broken links caused by the previous documentation site migration. If you run across a link in the wild that results in a "404", find the correct page and create a redirect from the old to the new. + +## Creating page content + +All content is created as markdown and rendered to HTML using the [MkDocs](https://www.mkdocs.org) project. The docs are written in standard markdown, not GitHub Flavored markdown but there are lots of extensions available. See [Markdown extensions](#markdown-extensions) below. + +Much of the feature set available to content authors is actually used to create this page. Browse the source to see how this page was created. [Contributing-to-the-Documentation.md](https://github.com/asterisk/documentation/blob/main/docs/Contributing-to-the-Documentation.md) + +### Front matter + +Many of the pages converted from the old Confluence wiki have "front matter" at the top of the markdown file. For instance: + +```yaml +--- +title: Asterisk Community Services +pageid: 24838288 +--- +``` + +Although supported, there's no longer any need to specify front matter except for specific circumstances noted below. + +/// warning +If there's a front-matter fragment at the top of the file and it contains a "title" entry, it will override the top-level header as the page name in the left sidebar. For this reason, if you're editing a page that has front-matter that specifies a "title", it's a good idea to make sure the page has a top-level header with the correct title and just remove the front-matter altogether. See [Headings](#headings) below for more info. +/// + +### Headings + +All headings MUST use the hash-sign header format and there MUST be only one top-level (`#`) header. For example: + +```markdown title="Good" +# Header level 1 +## Header level 2 +``` + +```markdown title="BAD - Multiple top-level headers" +# Header level 1 +## Header level 2 +# Another level 1 +``` + +```markdown title="BAD - Old style headers" +Header level 1 +============== +Header level 2 +----------------- +Another level 1 +============== +``` + +```markdown title="BAD - Front-matter title overrides top-level header" +--- +title: Original Page Title +--- +# New Page Title +## Header level 2 +``` + +The top-level header will override the file name as the page title in the left sidebar. The URL will still reference that actual file name and if the page is listed in a `.pages` file it must also be referenced by the actual file name. + +Nothing says you _have_ to have a top-level header but it is good practice and you should include it unless you have a good reason not to. It should always be Title Case. The lower level headers have no case restrictions. Use whatever looks best. + +### The Table of Contents + +The table of contents that appears on the right side of pages is automatically generated from the headers present in the page and an HTML "anchor" is created for each. The anchor is created by converting the header text to all lower case, converting spaces to dashes (`-`) and removing any characters not in the set `[a-z0-9-]`. The anchor for this section would be `the-table-of-contents` + +If, for some reason, you need to hide the ToC for a page, you can do it in the front-matter. For example: + +```yaml +--- +hide: + - toc +--- +``` + +This is really the only valid use of front-matter now. + +### Linking + +#### Linking to your supporting artifacts + +If you have supporting artifacts you need to link to or embed in your page and those artifacts are in the same directory as your page, the syntax is simple: + +```markdown title="Example linking to a supporting document" +[Sample Configuration](sample_config.conf) +``` + +```markdown title="Embed a supporting image" +![Sample Image](sample_image.png) +``` + +#### Linking to another section in your document + +Each header defined in your page is automatically assigned an "anchor" reference consisting of the header text converted to lower case with spaces replaced by dashes. For instance the anchor for this section would be `linking-to-another-section-in-your-document`. If you wanted to create a link to this section in another place in your document, you'd reference it as follows: + +```markdown title="Example link to a local anchor" +[Linking to another section in your document](#linking-to-another-section-in-your-document) +``` + +The leading `#` in the URL is the standard way to referenece anchors in a document. + +#### Linking to other content on the Documentation website + +If the content is in the same directory or in a directory below the current directory you can use relative link. + +```markdown title="Example relative links" +[Some Page](Some_Page) +[Some Other Page](Some_Subsection/Some_Other_Page) +``` + +To link to other content on the website, use an absolute URL. + +```markdown title="Linking to other website content" +[Configuring Alternate Channel Storage Backends](/Configuration/Core-Configuration/Alternate-Channel-Storage-Backends) +``` + +The mkdocs documentation actually discourages using absolute links and would rather you use a relative link like `../../../Configuration/Core-Configuration/Alternate-Channel-Storage-Backends`. This is to accomodate sites where the documentation isn't hosted at the root of the website. The Asterisk documentation _is_ at the root level so relative links just make things difficult for us. Always use absolute links. + +Don't forget, you can link directly to a specific section in any page by using the heading's anchor... + +```markdown title="Exmaple link to a specific section in a page" +[POC Conclusions](/Configuration/Core-Configuration/Alternate-Channel-Storage-Backends/#poc-conclusions) +``` + +/// warning +Do NOT include the `.md` suffix of pages you link to. If that page maintainer decides to add supporting artifacts and changes the page to a directory with an `index.md` file in it, your link may break. When in doubt about what link to use, you can get it by simply hovering over the link to the page you want in the live site and noting the URL. +/// + +### Comments + +Although not usually needed, you can add comments to markdown files that won't be rendered on the website. For instance, it could be useful to explain why you formatted something the way you did so future maintainers don't accidentally undo it. The format is the same as it is for HTML: + +```title="Example comment in markdown" + +``` + +``` + +``` + +### Standard markdown text formatting + +All standard markdown formatting syntax. A good guide for basic syntax is [Markdown Guide](https://www.markdownguide.org/basic-syntax). Just don't use the "Alternate Syntax" for headings and use "fenced code blocks" (see below) instead of indented code blocks. + +### Markdown extensions + +Most extensions from the [PyMdown](https://facelessuser.github.io/pymdown-extensions/#extensions) plugin are available. The most useful include SuperFences (which handles code blocks) and Blocks (which handles admonitions). To see the list of extensions that are currently enabled for this site, see the "markdown_extensions" section at the bottom of the site's [mkdocs.yml](https://github.com/asterisk/documentation/blob/main/mkdocs.yml) file. + +Most of the extensions provided by [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/) are also enabled except those only available to paying sponsors and a few that don't make sense in this environment. Many of these are actually implemented using PyMdown. + +/// warning | Extension Preference +If the same extension is available in both PyMdown and Material for MkDocs, ALWAYS use the PyMdown version/syntax! +/// + +#### Code blocks + +Speaking of code blocks, you should always create "fenced" code blocks using the 'three-backtick' (\`\`\`) technique which can include syntax a highlighting hint and a title (among other things). For example: + +```` +```python title="A Sample Sample Python Function" linenums="10" + def SomeFunc(arg1): + print("hi") +``` +```` + +would produce: + +```python title="A Sample Python Function" linenums="10" + def SomeFunc(arg1): + print("hi") +``` + +You can also nest code blocks. This was required to show the example for the syntax above as well as the note below. Here's the example for above: + +````` +```` +```python title="A Sample Sample Python Function" + def SomeFunc(arg1): + print("hi") +``` +```` +````` + +That needed 3 levels of nesting to render properly :). + +/// note +Use "ini" as the syntax highlighting hint for Asterisk config files. For example: + +```` +```ini title="Sample extensions.conf file" +[default] + +exten = _X.,1,NoOp(nothing) +``` +```` + +```ini title="Sample extensions.conf file" +[default] + +exten = _X.,1,NoOp(nothing) +``` + +/// + +#### Admonitions + +Available admonitions include "note", "attention", "caution", "danger", "error", "tip", "hint", "warning" and "details". + +Examples: + +```title="Example Note" +/// note | This Is A Note +Take note of this. +/// +``` +/// note | This Is A Note +Take note of this. +/// + +And yes, you can nest them... + +```title="Example Note with Warning" +/// note | This Is A Note +Take note of this. +//// warning | But be warned about this! +Pay attention +//// +/// +``` + +/// note | This Is A Note +Take note of this. +/// warning | But be warned about this! +Pay attention +/// +/// + +/// danger | Danger! (this is a *real* admonition, not an example) +Most of the pages that were converted from the old Confluence wiki use the `!!!` admonition style. For example: + +``` +!!! tip + The `-R` option will also attach a remote console - however, it will attempt to automatically + reconnect to Asterisk if for some reason the connection is broken. This is particularly useful + if your remote console restarts Asterisk. + +[//]: # (end-tip) +``` + +That style is only supported for backwards compatibility and must not be used in new content. If you are editing a page with old style admonitions, you MUST convert them ALL to the new style. Mixing old and new styles will most probably cause the page to not be rendered correctly. + +/// + +#### Details + +"details" is a special type of admonition whose content is initially collapsed. + +```title="Example Details" +/// details | Summary +These details are initially collapsed. +/// +``` + +/// details | Summary +These details are initially collapsed. +/// + +You can set the type to change the icon and color if needed: + +```title="Example Details" +/// details | Summary + type: warning +These details are initially collapsed. +/// +``` + +/// details | Summary + type: warning +These details are initially collapsed. +/// + +/// danger | Danger! (another *real* admonition, not an example) +Don't over-use admonitions (like I did in this page :smile: )! It can be very distracting. +/// + +#### Snippets + +Another extension you might find useful is [Snippets](https://facelessuser.github.io/pymdown-extensions/extensions/snippets/). This extension allows you to include other files (or parts of other files) in your document. A good use case would be explaining sections of a sample config file. + +``` +docs/ + Configuration/ + My-New-Feature/ + index.md + sample_config.conf +``` + +In your index.md file you could not only have a link to the entire sample_config.conf file, but you could also include sections of that file in your markdown file: + +```` title="Include lines 5-10 from sample_config.conf in a code block" +```ini title="Example configuration" +;--8<-- "Configuration/My-New-Feature/sample_config.conf:5:10" +``` +```` + +Snippets are implemented as a pre-processor so you must always specify the path to the file to be included relative to the top-level docs directory. The file contents are included verbatim and can contain any valid markdown. + +#### Emojis + +Yes you can use emojis like `:smile:` but don't over do it. + +#### Tables + +Tables are fully supported. See the syntax in [Markdown Guide](https://www.markdownguide.org/extended-syntax/#tables). + +#### Diagrams and Graphs + +When the documentation site was hosted in a Confluence Wiki, the mechanism for creating diagrams was a Gliffy Confluence macro which allowed you to design diagrams in-line. You'll still see files in this repo with a `.gliffy.xml` file extension which contained the source for the diagram and a file with the `.png` extension right next to it with the rendered result. Although the `.png` files are still rendered correctly, the `.gliffy.xml` files are simply ignored. Since Gliffy is a Confluence-specific tool, we needed another way to create diagrams. This turned out to be [Mermaid](https://mermaid.js.org). + +You can use Mermaid to create over 20 types of diagrams and charts. There's no in-line visual editor to create the diagrams but the syntax is pretty simple. Here's a short example: + +```` title="Mermaid Flowchart Example" +--- +title: Flowchart Example +--- +flowchart LR + A[Hard edge] -->|Link text| B(Round edge) + B --> C{Decision} + C -->|One| D[Result one] + C -->|Two| E[Result two] +```` + +```mermaid +--- +title: Flowchart Example +--- +flowchart LR + A[Hard edge] -->|Link text| B(Round edge) + B --> C{Decision} + C -->|One| D[Result one] + C -->|Two| E[Result two] +``` + +Mermaid itself is a Javascript library but the [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin) takes care of all of the plumbing so all you have to do is describe the diagram you want. Visit the [Mermaid Diagram Syntax](https://mermaid.js.org/intro/syntax-reference.html) page to see all the different types of diagrams you can create and how to create them. + +Mermaid does have an [on-line playground](https://www.mermaidchart.com/app/dashboard) to help design diagrams and while the basic version is free, you do have to register to use it. Since you already have a GitHub account (or you wouldn't be here), you can use that to register with. You can then just copy the generated code and paste it into your page. Please don't export diagrams to images. That makes it impossible to edit them later. + + +### HTML in markdown + +For very rare cases where the markdown syntax already described above doesn't cover a case you absolutely need, you can embed _some_ HTML directly into your markdown. The only case that comes to mind is forcing a line break. + +```html title="Example HTML in markdown" +this is
+a broken
+line +``` + +this is
+a broken
+line + +This can be useful to force wrap the text in table cells. + +```title="Example line breaks in a table" +| Column 1 | Column 2
(optional) | +| ----------| ----------| +| cell 1 | For instance:
abc = ABC | +``` + +| Column 1 | Column 2
(optional) | +| ----------| ----------| +| cell 1 | For instance:
abc = ABC | + +## Building the documentation locally + +Once you've made your updates, you'll want to test it locally to make sure everything renders properly. + +### Setup the environment + +You've already cloned your fork of the documentation repo at this point but to set it up for building the documentation perform the following steps: + +```sh +# Install python3-virtualenv +$ sudo (apt | dnf | yum) install python3-virtualenv +$ cd asterisk-documentation +$ python3 -m venv --system-site-packages --symlinks .venv +$ source .venv/bin/activate +$ pip install -r requirements.txt +``` + +### Build the web site + +To build only the static documentation without any of the API documentation for the branches simlpy run `make`: + +```sh +$ make +``` + +This will take about 30 seconds. + +### Start up a web server. + +The rendered website will be located in the `./temp/site` directory. You can use the web server software of your choice to serve it but it's much simpler to use the mkdocs built-in webserver: + +```sh +$ make serve +``` + +By default the server is started on port 8000 but you can supply different arguments to the server by adding a SERVE_OPTS variable to the command line: + +```sh +$ make SERVE_OPTS='-a 0.0.0.0:8080' serve +``` + +Run `mkdocs serve --help` to see the options you can set. + +/// note +You can't browse the site using `file://` URLS without a web server. MkDocs generates `index.html` files assuming a web server's rules will automatically use them as the default page for directories. +/// + +### Save often-used variables in Makefile.inc + +The main Makefile automatically includes the `Makefile.inc` file if it exists. You can use this to define variables like SERVE_OPTS so you don't have to specify them on the command line every time. This file is ignored by git so don't check it in. + +## Dynamic Documentation + +The dynamic documentation includes the pages generated from Asterisk itself and includes: + +* AGI Commands +* AMI Actions +* AMI Events +* Asterisk REST Interface +* Dialplan Applications +* Dialplan Functions +* Module Configuration + +These will be rendered under the "Asterisk XX Documentation/API Documentation" directories where "XX" is the branch name. + +The publish process gets this information directly from the Asterisk CreateDocs job (which runs nightly) and generates markdown which MkDocs will then use to render the site. For this reason, all changes to the dynamic documentation need to be made in the Asterisk source code itself. + +The AGI, AMI, Dialplan and Module documentation comes from the XML documentation embedded in the provider modules and generated by CreateDocs running `xmldoc dump` from the Asterisk CLI. + +The Asterisk REST Interface documentation comes from the markdown files generated by CreateDocs running `make ari-stubs`. + +The nightly documentation "publish" performs the following steps: + +* Retrieves the XML and ARI markdown from the latest Asterisk CreateDocs workflow run for each branch. +* Runs `utils/astxml2markdown.py` on the retrieved XML and places the resulting markdown in the `temp/build-` directory. +* Places the retrieved ARI markdown in the `temp/build-` directory. +* Builds the website. + +#### Build the static documentation plus the dynamic API documentation for one or more branches. + +/// note +In order to build the dynamic documentation, you'll need to have the [GitHub CLI "gh"](https://cli.github.com) tool installed to retrieve the source files from the Asterisk nightly job that creates them. +/// + +/// attention +It can take 5 minutes or more to build the dynamic documentation _for each branch_ so don't do this unless you're sure you need to. HINT: You probably don't need to. +/// + +If you do need to generate the dynamic documentation, run `make` with a `BRANCHES` variable set to a comma-separated list of branches you want to build. + +```sh +$ make BRANCHES=21,22 +``` + +#### Test changes you've made to Asterisk source files + +Let's say you have actually made changes to the documentation contained in the Asterisk source files and want to see how it will be rendered. Instead of the documentation build process getting the Asterisk sources from the latest CreateDocs workflows, you can export the documentation and then tell the documentation build process where to get the files. + +The XML documentation for AGI, AMI, Dialplan and Module configuration has to be generated from a _running_ asterisk instance so build and start it. Then from the Asterisk CLI run `xmldoc dump /tmp/asterisk--documentation.xml`. + +The markdown for ARI resources and events is generated by running `make ari-stubs` in your Asterisk source directory. Asterisk doesn't need to be built or run for this. + +Once you've done both, create a new file in your documentation directory named `Makefile..inc`. These files are already ignored by git so don't check them in. + +```makefile title="Sample Makefile.22.inc file" +# If you want to use a local XML file to generate the +# AGI, AMI, Dialplan and Module_Configuration documentation, +# specify it here. +ASTERISK_XML_FILE := /tmp/asterisk-22-documentation.xml +# +# If you want to use local markdown files for the ARI +# documentation, specify a path to a directory containing +# the markdown generated by "make ari-stubs". +ASTERISK_ARI_DIR := /usr/src/asterisk/asterisk/doc/rest-api +# +# If you want to use local XML but skip processing ARI +# altogether, set this variable to "yes". +#SKIP_ARI := no + +# If either ASTERISK_XML_FILE or ASTERISK_ARI_DIR are not set, +# that documentation source will be downloaded from the +# CreateDocs job. +``` + +Now run `make`: + +```shell +$ make BRANCHES=22 +``` + +The main Makefile will automatically include the Makefile..inc file for any branch listed in BRANCHES. It doesn't make sense to build more than one branch in this situation but you could if you wanted to. You'll have to make sure there's a `Makefile..inc` file for each branch you want to build and that the paths in each file are adjusted to that branch's Asterisk files. diff --git a/mkdocs.yml b/mkdocs.yml index c26625d37c..61afcf5e10 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -87,6 +87,7 @@ plugins: - pre - code cache_safe: false + - mermaid2 extra: analytics: @@ -104,7 +105,6 @@ extra: - icon: fontawesome/brands/discourse link: https://community.asterisk.org - markdown_extensions: - abbr - attr_list @@ -139,13 +139,13 @@ markdown_extensions: - pymdownx.saneheaders - pymdownx.smartsymbols - pymdownx.snippets: - base_path: '/' + base_path: './docs' check_paths: true - pymdownx.superfences: custom_fences: - name: mermaid class: mermaid - format: !!python/name:pymdownx.superfences.fence_code_format + format: !!python/name:mermaid2.fence_mermaid_custom - pymdownx.tilde diff --git a/requirements.txt b/requirements.txt index 02832677aa..01a27a23c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,11 @@ mkdocs==1.6.1 -mkdocs-awesome-pages-plugin==2.9.3 +mkdocs-awesome-pages-plugin==2.10.1 mkdocs-git-revision-date-localized-plugin==1.3.0 -mkdocs-material==9.5.49 +mkdocs-material==9.6.19 mkdocs-material-extensions==1.3.1 mkdocs-minify-plugin==0.8.0 mkdocs-table-reader-plugin==3.1.0 lxml==5.3.0 -pymdown-extensions==10.12 +pymdown-extensions==10.16 mkdocs-redirects==1.2.2 +mkdocs_mermaid2_plugin==1.2.2 From b293183322511c2d03890b9da901ef3b4679ebc8 Mon Sep 17 00:00:00 2001 From: "Joshua C. Colp" Date: Thu, 18 Sep 2025 10:50:49 -0300 Subject: [PATCH 2/5] Asterisk-Versions: Fix dates for 23, and clarify incorrect lifecycle for 21. --- docs/About-the-Project/Asterisk-Versions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/About-the-Project/Asterisk-Versions.md b/docs/About-the-Project/Asterisk-Versions.md index 676cfd855f..1a90d61eb9 100644 --- a/docs/About-the-Project/Asterisk-Versions.md +++ b/docs/About-the-Project/Asterisk-Versions.md @@ -28,9 +28,9 @@ The following table shows the release time lines for all releases of Asterisk, i | 18.x | LTS | [2020-10-20](http://lists.digium.com/pipermail/asterisk-announce/2020-October/000791.html) | 2024-10-20 | 2025-10-20 | Security Fix Only | | 19.x | Standard | 2021-11-02 | 2022-11-02 | 2023-11-02 | EOL | | 20.x | LTS | 2022-10-19 | 2026-10-19 | 2027-10-19 | Fully Supported | -| 21.x | Standard | 2023-10-18 | 2025-10-18 | 2026-10-18 | Fully Supported | +| 21.x | Standard | 2023-10-18 | 2025-10-18 | 2026-10-18 | Fully Supported (Due to a mistake in scheduling this was supported for 2 years for bug fixes) | | 22.x | LTS | 2024-10-16 | 2028-10-16 | 2029-10-16 | Fully Supported | -| 23.x | Standard | 2025-10-15 | 2027-10-15 | 2028-10-15 | Fully Supported | +| 23.x | Standard | 2025-10-15 | 2026-10-15 | 2027-10-15 | Fully Supported | New releases of Asterisk will be made roughly once a year, alternating between standard and LTS releases. Within a given release series that is fully supported, bug fix updates are provided roughly every 4 to 6 weeks. For a release series that is receiving only maintenance for security fixes, updates are made on an as needed basis. From 30fc09557be62f8ac20eb1c49f7333d33f441311 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Thu, 18 Sep 2025 12:36:46 -0600 Subject: [PATCH 3/5] WebSocket: Add info for the p and v parameters --- .../Channel-Drivers/WebSocket.md | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/Configuration/Channel-Drivers/WebSocket.md b/docs/Configuration/Channel-Drivers/WebSocket.md index d198047c79..da45ccde86 100644 --- a/docs/Configuration/Channel-Drivers/WebSocket.md +++ b/docs/Configuration/Channel-Drivers/WebSocket.md @@ -2,7 +2,7 @@ ## Background -The WebSocket Channel Driver (chan_websocket) is designed to ease the burden on ARI application developers with getting media in and out of Asterisk. The ARI /channels/externalMedia REST endpoint already has two other channel drivers available (AudioSocket and RTP) but they require binary packet manipulation (RTP especially) and both require that the app developer handle the timing of sending packets to asterisk. chan_websocket requires neither. The new driver will be available starting with Asterisk releases 22.6.0, 21.11.0 and 20.16.0. +The WebSocket Channel Driver (chan_websocket) is designed to ease the burden on ARI application developers with getting media in and out of Asterisk. The ARI /channels/externalMedia REST endpoint already has two other channel drivers available (AudioSocket and RTP) but they require binary packet manipulation (RTP especially) and both require that the app developer handle the timing of sending packets to asterisk. chan_websocket requires neither. The new driver will be available starting with Asterisk releases 23.0.0, 22.6.0, 21.11.0 and 20.16.0. ## Features @@ -46,7 +46,11 @@ Whether inbound or outbound, the default behavior is to automatically answer the Media sent from Asterisk to your application is simply streamed in BINARY websocket messages. The message size will be whatever the internal Asterisk frame size is. For ulaw/alaw for instance, Asterisk will send a 160 byte packet every 20ms. This is the same as RTP except the messages will contain raw media with no RTP or other headers. You could stream this directly to a file or other service. -Media sent _to_ Asterisk _from_ your app is a bit trickier because chances are that the media you send Asterisk will eventually need to go out to a caller in a format that is both properly framed and properly timed. I.E. 160 byte blocks every 20 ms for a/ulaw. Sending short, long or mistimed packets will surely result is poor audio quality. To relieve your app of the burden of having to do the framing and timing, the channel driver will do it automatically but there are a few rules you have to follow. +Media sent _to_ Asterisk _from_ your app is a bit trickier because chances are that the media you send Asterisk will eventually need to go out to a caller in a format that is both properly framed and properly timed. I.E. 160 byte blocks every 20 ms for a/ulaw. Sending short, long or mistimed packets will surely result is poor audio quality. To relieve your app of the burden of having to do the framing and timing, the channel driver will do it automatically for most codecs but there are a few exceptions and rules you have to follow. + +/// warning +There currently is no way for chan_websocket to re-frame or re-time variable bitrate, variable bandwidth and/or variable encoding rate media. For this reason, codecs like opus must be used in ["passthrough mode"](#passthrough-mode) (see below) where the application is responsible for correctly framing and timing the media it sends to Asterisk. +/// When the websocket channel is created, a `MEDIA_WEBSOCKET_OPTIMAL_FRAME_SIZE` channel variable will be set that tells you the amount of data Asterisk needs to create a good 20ms frame using the codec you specified in the dialstring. This is also reported in the `MEDIA_START` TEXT message. If you send a websocket message with a length that's exactly that size or some even multiple of that size, the channel driver will happily break that message up into the correctly sized frames and send one frame to the Asterisk core every 20ms with no leftover data. If you send an oddly sized message though, the extra data that won't fill a frame will be dropped. However... @@ -89,23 +93,23 @@ Some of the control TEXT messages you can send the driver have already been ment `START_MEDIA_BUFFERING` -- Indicates to the channel driver that the following media should be buffered to create properly sized and timed frames. +- Indicates to the channel driver that the following media should be buffered to create properly sized and timed frames. Not applicable in passthrough mode. `STOP_MEDIA_BUFFERING ` -- Indicates to the channel driver that buffering is no longer needed and anything remaining in the buffer should have silence appended before sending to the Asterisk core. When the last frame of this bulk transfer has been sent to the core, the app will receive a `MEDIA_BUFFERING_COMPLETED` notification. If the optional id was specified in this command, it'll be returned in the notification. If you send multiple files in quick succession, the id can help you correlate the `MEDIA_BUFFERING_COMPLETED` notification to the `STOP_MEDIA_BUFFERING` command that triggered it. +- Indicates to the channel driver that buffering is no longer needed and anything remaining in the buffer should have silence appended before sending to the Asterisk core. When the last frame of this bulk transfer has been sent to the core, the app will receive a `MEDIA_BUFFERING_COMPLETED` notification. If the optional id was specified in this command, it'll be returned in the notification. If you send multiple files in quick succession, the id can help you correlate the `MEDIA_BUFFERING_COMPLETED` notification to the `STOP_MEDIA_BUFFERING` command that triggered it. Not applicable in passthrough mode. `FLUSH_MEDIA` -- Send this command to the channel driver if you've sent a large amount of media but want to discard any queued but not sent. Flushing the buffer automatically ends any bulk transfer in progress and also resets the paused state so there's no need to send `STOP_MEDIA_BUFFERING` or `CONTINUE_MEDIA` commands. No `MEDIA_BUFFERING_COMPLETED` notification will be sent in this case but you could send a `REPORT_QUEUE_DRAINED` command (see below) before sending the `MEDIA_FLUSH` to get a confirmation that the queue was indeed flushed. This command could be useful if an automated agent detects the caller is speaking and wants to interrupt a prompt it already replied with. +- Send this command to the channel driver if you've sent a large amount of media but want to discard any queued but not sent. Flushing the buffer automatically ends any bulk transfer in progress and also resets the paused state so there's no need to send `STOP_MEDIA_BUFFERING` or `CONTINUE_MEDIA` commands. No `MEDIA_BUFFERING_COMPLETED` notification will be sent in this case but you could send a `REPORT_QUEUE_DRAINED` command (see below) before sending the `MEDIA_FLUSH` to get a confirmation that the queue was indeed flushed. This command could be useful if an automated agent detects the caller is speaking and wants to interrupt a prompt it already replied with. Not applicable in passthrough mode. `PAUSE_MEDIA` -- If you've sent a large amount of media but need to pause it playing to a caller while you decide if you need to flush it or not, you can send a `PAUSE_MEDIA` command. The channel driver will then start playing silence to the caller but keep the data you've already sent in the queue. You can still send media to the channel driver while it's paused; it'll just get queued behind whatever was already in the queue. +- If you've sent a large amount of media but need to pause it playing to a caller while you decide if you need to flush it or not, you can send a `PAUSE_MEDIA` command. The channel driver will then start playing silence to the caller but keep the data you've already sent in the queue. You can still send media to the channel driver while it's paused; it'll just get queued behind whatever was already in the queue. Not applicable in passthrough mode. `CONTINUE_MEDIA` -- If you've previously paused the media, this will cause the channel driver to stop playing silence and resume playing media from the queue from the point you paused it. +- If you've previously paused the media, this will cause the channel driver to stop playing silence and resume playing media from the queue from the point you paused it. Not applicable in passthrough mode. `GET_STATUS` @@ -113,7 +117,7 @@ Some of the control TEXT messages you can send the driver have already been ment `REPORT_QUEUE_DRAINED` -- This will cause the channel driver to send back a one-time `QUEUE_DRAINED` notification the next time it detects that there are no more frames to process in the queue. +- This will cause the channel driver to send back a one-time `QUEUE_DRAINED` notification the next time it detects that there are no more frames to process in the queue. Not applicable in passthrough mode. /// @@ -127,6 +131,10 @@ Some of the control TEXT messages you can send the driver have already been ment Example: `MEDIA_START connection_id:e226e283-c90a-4ea9-9e37-389000b9ef47 channel:WebSocket/connectionid format:ulaw optimal_frame_size:160`
Not only does this notification contain the optimal frame size and format, it also contains the channel name and connection id which you can use to correlate incoming connections from the driver to channels you've created. +`DTMF_END` + +- The channel driver will send this notification when DTMF_END frames are received from the core. The format will be `DTMF_END digit:n` where `n` is the DTMF digit. + `MEDIA_XOFF` - The channel driver will send this notification to the app when the frame queue length reaches the high water (XOFF) level. The app should then pause sending media. Any media sent after this has a high probability of being dropped. @@ -174,11 +182,14 @@ Dial(WebSocket//[,[,]]) * **<options>**: * `c()`: If not specified, the first codec from the caller's channel will be used. Having said that, if your app is expecting a specific codec, you should specify it here or you may be getting audio in a format you don't expect. * `n`: Don't auto-answer the WebSocket channel upon successful connection. Set this if you wish to answer the channel yourself. You can then send an `ANSWER` TEXT message on the websocket when you're ready to answer the channel or make a `/channels//answer` REST call. + * `p`: [](){ #passthrough-mode } Passthrough mode - In passthrough mode, the channel driver won't attempt to re-frame or re-time media coming in over the websocket from the remote app. This must be used for variable-bitrate, variable-bandwidth, and/or variable-encoding-rate codecs like Opus because there's no way for the channel driver to create correctly sized frames. In this case, the remote app is fully responsible for correctly framing and timing media sent to Asterisk. + * `v()`: Add parameters to the outbound URI. This option allows you to add additional parameters to the outbound URI. The format is: 'v(param1=value1,param2=value2...)'. You must ensure that no parameter name or value contains characters not valid in a URL. The easiest way to do this is to use the URIENCODE() dialplan function to encode them. Be aware though that each name and value must be encoded separately. You can't simply encode the whole string. Examples: ``` title="Dial() Examples" Dial(WebSocket/connection1/c(alaw)n) +Dial(WebSocket/connection1/c(opus)p) Dial(WebSocket/INCOMING/c(slin16)) ``` From 5599bb34b76eaccce557143a5553390d76f11e87 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Fri, 19 Sep 2025 09:10:35 -0600 Subject: [PATCH 4/5] WebSocket: Update passthrough mode --- .../Channel-Drivers/WebSocket.md | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/docs/Configuration/Channel-Drivers/WebSocket.md b/docs/Configuration/Channel-Drivers/WebSocket.md index da45ccde86..01dae4d931 100644 --- a/docs/Configuration/Channel-Drivers/WebSocket.md +++ b/docs/Configuration/Channel-Drivers/WebSocket.md @@ -49,7 +49,7 @@ Media sent from Asterisk to your application is simply streamed in BINARY websoc Media sent _to_ Asterisk _from_ your app is a bit trickier because chances are that the media you send Asterisk will eventually need to go out to a caller in a format that is both properly framed and properly timed. I.E. 160 byte blocks every 20 ms for a/ulaw. Sending short, long or mistimed packets will surely result is poor audio quality. To relieve your app of the burden of having to do the framing and timing, the channel driver will do it automatically for most codecs but there are a few exceptions and rules you have to follow. /// warning -There currently is no way for chan_websocket to re-frame or re-time variable bitrate, variable bandwidth and/or variable encoding rate media. For this reason, codecs like opus must be used in ["passthrough mode"](#passthrough-mode) (see below) where the application is responsible for correctly framing and timing the media it sends to Asterisk. +There currently is no way for chan_websocket to re-frame or re-time codecs whose data streams contain packet headers or can't be broken up on arbitrary byte/sample boundaries. For this reason, codecs like opus and speex are handled in ["passthrough mode"](#passthrough-mode) where the application is responsible for correctly framing and timing the media it sends to Asterisk. /// When the websocket channel is created, a `MEDIA_WEBSOCKET_OPTIMAL_FRAME_SIZE` channel variable will be set that tells you the amount of data Asterisk needs to create a good 20ms frame using the codec you specified in the dialstring. This is also reported in the `MEDIA_START` TEXT message. If you send a websocket message with a length that's exactly that size or some even multiple of that size, the channel driver will happily break that message up into the correctly sized frames and send one frame to the Asterisk core every 20ms with no leftover data. If you send an oddly sized message though, the extra data that won't fill a frame will be dropped. However... @@ -91,25 +91,25 @@ Some of the control TEXT messages you can send the driver have already been ment - This will cause the WebSocket channel to be hung up and the websocket to be closed. -`START_MEDIA_BUFFERING` +`START_MEDIA_BUFFERING`[^1^](#fn1) -- Indicates to the channel driver that the following media should be buffered to create properly sized and timed frames. Not applicable in passthrough mode. +- Indicates to the channel driver that the following media should be buffered to create properly sized and timed frames. -`STOP_MEDIA_BUFFERING ` +`STOP_MEDIA_BUFFERING `[^1^](#fn1) -- Indicates to the channel driver that buffering is no longer needed and anything remaining in the buffer should have silence appended before sending to the Asterisk core. When the last frame of this bulk transfer has been sent to the core, the app will receive a `MEDIA_BUFFERING_COMPLETED` notification. If the optional id was specified in this command, it'll be returned in the notification. If you send multiple files in quick succession, the id can help you correlate the `MEDIA_BUFFERING_COMPLETED` notification to the `STOP_MEDIA_BUFFERING` command that triggered it. Not applicable in passthrough mode. +- Indicates to the channel driver that buffering is no longer needed and anything remaining in the buffer should have silence appended before sending to the Asterisk core. When the last frame of this bulk transfer has been sent to the core, the app will receive a `MEDIA_BUFFERING_COMPLETED` notification. If the optional id was specified in this command, it'll be returned in the notification. If you send multiple files in quick succession, the id can help you correlate the `MEDIA_BUFFERING_COMPLETED` notification to the `STOP_MEDIA_BUFFERING` command that triggered it. -`FLUSH_MEDIA` +`FLUSH_MEDIA`[^1^](#fn1) -- Send this command to the channel driver if you've sent a large amount of media but want to discard any queued but not sent. Flushing the buffer automatically ends any bulk transfer in progress and also resets the paused state so there's no need to send `STOP_MEDIA_BUFFERING` or `CONTINUE_MEDIA` commands. No `MEDIA_BUFFERING_COMPLETED` notification will be sent in this case but you could send a `REPORT_QUEUE_DRAINED` command (see below) before sending the `MEDIA_FLUSH` to get a confirmation that the queue was indeed flushed. This command could be useful if an automated agent detects the caller is speaking and wants to interrupt a prompt it already replied with. Not applicable in passthrough mode. +- Send this command to the channel driver if you've sent a large amount of media but want to discard any queued but not sent. Flushing the buffer automatically ends any bulk transfer in progress and also resets the paused state so there's no need to send `STOP_MEDIA_BUFFERING` or `CONTINUE_MEDIA` commands. No `MEDIA_BUFFERING_COMPLETED` notification will be sent in this case but you could send a `REPORT_QUEUE_DRAINED` command (see below) before sending the `MEDIA_FLUSH` to get a confirmation that the queue was indeed flushed. This command could be useful if an automated agent detects the caller is speaking and wants to interrupt a prompt it already replied with. -`PAUSE_MEDIA` +`PAUSE_MEDIA`[^1^](#fn1) -- If you've sent a large amount of media but need to pause it playing to a caller while you decide if you need to flush it or not, you can send a `PAUSE_MEDIA` command. The channel driver will then start playing silence to the caller but keep the data you've already sent in the queue. You can still send media to the channel driver while it's paused; it'll just get queued behind whatever was already in the queue. Not applicable in passthrough mode. +- If you've sent a large amount of media but need to pause it playing to a caller while you decide if you need to flush it or not, you can send a `PAUSE_MEDIA` command. The channel driver will then start playing silence to the caller but keep the data you've already sent in the queue. You can still send media to the channel driver while it's paused; it'll just get queued behind whatever was already in the queue. -`CONTINUE_MEDIA` +`CONTINUE_MEDIA`[^1^](#fn1) -- If you've previously paused the media, this will cause the channel driver to stop playing silence and resume playing media from the queue from the point you paused it. Not applicable in passthrough mode. +- If you've previously paused the media, this will cause the channel driver to stop playing silence and resume playing media from the queue from the point you paused it. `GET_STATUS` @@ -119,8 +119,13 @@ Some of the control TEXT messages you can send the driver have already been ment - This will cause the channel driver to send back a one-time `QUEUE_DRAINED` notification the next time it detects that there are no more frames to process in the queue. Not applicable in passthrough mode. +Footnotes: + +- [](){ #fn1 }1: Not applicable in [passthrough mode](#passthrough-mode). + /// + #### Notifications /// define @@ -182,14 +187,22 @@ Dial(WebSocket//[,[,]]) * **<options>**: * `c()`: If not specified, the first codec from the caller's channel will be used. Having said that, if your app is expecting a specific codec, you should specify it here or you may be getting audio in a format you don't expect. * `n`: Don't auto-answer the WebSocket channel upon successful connection. Set this if you wish to answer the channel yourself. You can then send an `ANSWER` TEXT message on the websocket when you're ready to answer the channel or make a `/channels//answer` REST call. - * `p`: [](){ #passthrough-mode } Passthrough mode - In passthrough mode, the channel driver won't attempt to re-frame or re-time media coming in over the websocket from the remote app. This must be used for variable-bitrate, variable-bandwidth, and/or variable-encoding-rate codecs like Opus because there's no way for the channel driver to create correctly sized frames. In this case, the remote app is fully responsible for correctly framing and timing media sent to Asterisk. + * `p`: [](){ #passthrough-mode } Passthrough mode - In passthrough mode, the channel driver won't attempt to re-frame or re-time media coming in over the websocket from the remote app. This can be used for any codec but MUST be used for codecs that use packet headers or whose data stream can't be broken up on arbitrary byte/sample boundaries. In this case, the remote app is fully responsible for correctly framing and timing media sent to Asterisk and the MEDIA text commands that could be sent over the websocket are disabled. Currently, passthrough mode is automatically set for the opus, speex and g729 codecs. * `v()`: Add parameters to the outbound URI. This option allows you to add additional parameters to the outbound URI. The format is: 'v(param1=value1,param2=value2...)'. You must ensure that no parameter name or value contains characters not valid in a URL. The easiest way to do this is to use the URIENCODE() dialplan function to encode them. Be aware though that each name and value must be encoded separately. You can't simply encode the whole string. Examples: ``` title="Dial() Examples" +; Make an outbound connection using the alaw codec but don't auto-answer the channel +; when the remote application connects. Dial(WebSocket/connection1/c(alaw)n) -Dial(WebSocket/connection1/c(opus)p) + +; Make an outbound connection using the opus codec adding the "chan" and "exten" +; parameters to the URI. Passthrough mode is automatically set for the opus codec. +Dial(WebSocket/connection1/c(opus)v(chan=${URIENCODE(${CHANNEL})},exten=$(URIENCODE(${EXTEN})})) + +; Wait for an incoming websocket connection from a remote application and pass media +; using the slin16 codec. Dial(WebSocket/INCOMING/c(slin16)) ``` From 3b592f6c542247134eb476d5cd0208e93eb59e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6ran=20Vinzens?= Date: Fri, 19 Sep 2025 08:31:52 +0200 Subject: [PATCH 5/5] feat: ARI transfer handling - configuration improvements also: there is no automatically generated NOTIFY --- .../index.md | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Introduction-to-ARI-Transfer-Handling/index.md b/docs/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Introduction-to-ARI-Transfer-Handling/index.md index 2092a893dd..bdf04a46ad 100644 --- a/docs/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Introduction-to-ARI-Transfer-Handling/index.md +++ b/docs/Configuration/Interfaces/Asterisk-REST-Interface-ARI/Introduction-to-ARI-Transfer-Handling/index.md @@ -20,6 +20,31 @@ In SIP there is a method called `REFER`. This method, if triggered by the user, Asterisk handles the REFER without any config changes by itself. To have ARI handle the transfer you need to change a setting so the ARI events are generated. If done, the `channelTransferEvent` will be generated in case a `REFER` is received. The `channelTransferEvent` contains the information about the transfer. The `channelTransferEvent` is generated for both, blind and attended transfer. + +### Configuration + +To enable ARI transfer handling, set [PJSIP_TRANSFER_HANDLING()=ari-only](https://docs.asterisk.org/Latest_API/API_Documentation/Dialplan_Functions/PJSIP_TRANSFER_HANDLING/). + +• Endpoint configuration: + +``` +set_var=PJSIP_TRANSFER_HANDLING()=ari-only +``` + +All channels from this endpoint will inherit the setting. + +• Dialplan: + +``` +same => n,Set(PJSIP_TRANSFER_HANDLING()=ari-only) +``` + +Apply before sending the channel to a Stasis application. + +• ARI-created channels: + +Set the variable at channel creation. See the [ARI REST documentation](https://docs.asterisk.org/Latest_API/API_Documentation/Asterisk_REST_Interface/Channels_REST_API/#create) for details. + ### Information within the `channelTransferEvent` #### Attended transfer @@ -61,7 +86,14 @@ Where the channel marked with the "X" might be placed on hold, or not. ### Actions after the event is received #### Attended transfer -The ARI application MUST take some action in order to handle the REFER. The Asterisk will not do anything by itself. The first thing to do when received an SIP REFER is acknowledge it. This is done by the Asterisk, as well as the first `NOTIFY` telling the telephone an `100 Trying` SIP frag. After that, the telephon waits for a `Notify` containing a SIP frag with `200 OK`. This has to be sent by the ARI application manually. +The ARI application MUST take action in order to handle a SIP REFER. Asterisk does not handle the transfer automatically. + +When a REFER is received, Asterisk will acknowledge it with a `202 Accepted`. After that, it is the responsibility of the ARI application to send the required NOTIFY messages to the transferrer. This includes: + +* An initial NOTIFY with a SIP frag of `100 Trying` +* Subsequent NOTIFY messages with updated status, such as a SIP frag of `200 OK` once the transfer is complete, or an appropriate error if the transfer fails + +If the ARI application does not send these NOTIFY messages, the transferrer will never receive progress or completion information for the transfer. Actions that should be taken by the ARI application in the scenario described in call schema 1: