]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
ARI: Add command to indicate progress to a channel
authorSven Kube <mail@sven-kube.de>
Wed, 30 Jul 2025 12:24:07 +0000 (14:24 +0200)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 18 Aug 2025 16:29:53 +0000 (16:29 +0000)
Adds an ARI command to send a progress indication to a channel.

DeveloperNote: A new ARI endpoint is available at `/channels/{channelId}/progress` to indicate progress to a channel.

include/asterisk/stasis_app.h
res/ari/resource_channels.c
res/ari/resource_channels.h
res/res_ari_channels.c
res/stasis/control.c
rest-api/api-docs/channels.json

index e005a1fa7eb61f26101cd54ed1909ffeb8fafbe3..8a41f555d0631f6b69c0e81c7eaa5d6033a919d6 100644 (file)
@@ -568,6 +568,16 @@ int stasis_app_control_ring(struct stasis_app_control *control);
  */
 int stasis_app_control_ring_stop(struct stasis_app_control *control);
 
+/*!
+ * \brief Indicate progress to the channel associated with this control.
+ *
+ * \param control Control for \c res_stasis.
+ *
+ * \return 0 for success.
+ * \return -1 for error.
+ */
+int stasis_app_control_progress(struct stasis_app_control *control);
+
 /*!
  * \brief Send DTMF to the channel associated with this control.
  *
index dcedae1880b824e1341247cfed1372035a53d6b8..8218896f0ec91db77aaf5ac76fb459e9be918100 100644 (file)
@@ -401,6 +401,26 @@ void ast_ari_channels_ring_stop(struct ast_variable *headers,
        ast_ari_response_no_content(response);
 }
 
+void ast_ari_channels_progress(struct ast_variable *headers,
+       struct ast_ari_channels_progress_args *args,
+       struct ast_ari_response *response)
+{
+       RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+       control = find_control(response, args->channel_id);
+       if (control == NULL) {
+               return;
+       }
+
+       if (channel_state_invalid(control, response)) {
+               return;
+       }
+
+       stasis_app_control_progress(control);
+
+       ast_ari_response_no_content(response);
+}
+
 void ast_ari_channels_mute(struct ast_variable *headers,
        struct ast_ari_channels_mute_args *args,
        struct ast_ari_response *response)
index 96e2695fa32a9f1baba3674463761d891dbc66d2..b79f5f0255bb202e722fd2ba6b2c12a486df5e21 100644 (file)
@@ -358,6 +358,19 @@ struct ast_ari_channels_ring_stop_args {
  * \param[out] response HTTP response
  */
 void ast_ari_channels_ring_stop(struct ast_variable *headers, struct ast_ari_channels_ring_stop_args *args, struct ast_ari_response *response);
+/*! Argument struct for ast_ari_channels_progress() */
+struct ast_ari_channels_progress_args {
+       /*! Channel's id */
+       const char *channel_id;
+};
+/*!
+ * \brief Indicate progress on a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_channels_progress(struct ast_variable *headers, struct ast_ari_channels_progress_args *args, struct ast_ari_response *response);
 /*! Argument struct for ast_ari_channels_send_dtmf() */
 struct ast_ari_channels_send_dtmf_args {
        /*! Channel's id */
index 9c7b25182f08c3d79c866286b77a63f51c529b00..b37e8307539f138111b5b3bcbbe03f34c42346e3 100644 (file)
@@ -1157,6 +1157,68 @@ static void ast_ari_channels_ring_stop_cb(
        }
 #endif /* AST_DEVMODE */
 
+fin: __attribute__((unused))
+       return;
+}
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}/progress.
+ * \param ser TCP/TLS session object
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param body
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_progress_cb(
+       struct ast_tcptls_session_instance *ser,
+       struct ast_variable *get_params, struct ast_variable *path_vars,
+       struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
+{
+       struct ast_ari_channels_progress_args args = {};
+       struct ast_variable *i;
+#if defined(AST_DEVMODE)
+       int is_valid;
+       int code;
+#endif /* AST_DEVMODE */
+
+       for (i = path_vars; i; i = i->next) {
+               if (strcmp(i->name, "channelId") == 0) {
+                       args.channel_id = (i->value);
+               } else
+               {}
+       }
+       ast_ari_channels_progress(headers, &args, response);
+#if defined(AST_DEVMODE)
+       code = response->response_code;
+
+       switch (code) {
+       case 0: /* Implementation is still a stub, or the code wasn't set */
+               is_valid = response->message == NULL;
+               break;
+       case 500: /* Internal Server Error */
+       case 501: /* Not Implemented */
+       case 404: /* Channel not found */
+       case 409: /* Channel not in a Stasis application */
+       case 412: /* Channel in invalid state */
+               is_valid = 1;
+               break;
+       default:
+               if (200 <= code && code <= 299) {
+                       is_valid = ast_ari_validate_void(
+                               response->message);
+               } else {
+                       ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/progress\n", code);
+                       is_valid = 0;
+               }
+       }
+
+       if (!is_valid) {
+               ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/progress\n");
+               ast_ari_response_error(response, 500,
+                       "Internal Server Error", "Response validation failed");
+       }
+#endif /* AST_DEVMODE */
+
 fin: __attribute__((unused))
        return;
 }
@@ -3145,6 +3207,15 @@ static struct stasis_rest_handlers channels_channelId_ring = {
        .children = {  }
 };
 /*! \brief REST handler for /api-docs/channels.json */
+static struct stasis_rest_handlers channels_channelId_progress = {
+       .path_segment = "progress",
+       .callbacks = {
+               [AST_HTTP_POST] = ast_ari_channels_progress_cb,
+       },
+       .num_children = 0,
+       .children = {  }
+};
+/*! \brief REST handler for /api-docs/channels.json */
 static struct stasis_rest_handlers channels_channelId_dtmf = {
        .path_segment = "dtmf",
        .callbacks = {
@@ -3286,8 +3357,8 @@ static struct stasis_rest_handlers channels_channelId = {
                [AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb,
                [AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
        },
-       .num_children = 17,
-       .children = { &channels_channelId_continue,&channels_channelId_move,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial,&channels_channelId_rtp_statistics,&channels_channelId_transfer_progress, }
+       .num_children = 18,
+       .children = { &channels_channelId_continue,&channels_channelId_move,&channels_channelId_redirect,&channels_channelId_answer,&channels_channelId_ring,&channels_channelId_progress,&channels_channelId_dtmf,&channels_channelId_mute,&channels_channelId_hold,&channels_channelId_moh,&channels_channelId_silence,&channels_channelId_play,&channels_channelId_record,&channels_channelId_variable,&channels_channelId_snoop,&channels_channelId_dial,&channels_channelId_rtp_statistics,&channels_channelId_transfer_progress, }
 };
 /*! \brief REST handler for /api-docs/channels.json */
 static struct stasis_rest_handlers channels_externalMedia = {
index 74ebccdda2907cab34620f885e5bf9c0ddad3b96..256248ee751e591b385beaef2fafe83f17ee5baf 100644 (file)
@@ -637,6 +637,21 @@ int stasis_app_control_ring_stop(struct stasis_app_control *control)
        return 0;
 }
 
+static int app_control_progress(struct stasis_app_control *control,
+       struct ast_channel *chan, void *data)
+{
+       ast_indicate(control->channel, AST_CONTROL_PROGRESS);
+
+       return 0;
+}
+
+int stasis_app_control_progress(struct stasis_app_control *control)
+{
+       stasis_app_send_command_async(control, app_control_progress, NULL, NULL);
+
+       return 0;
+}
+
 struct stasis_app_control_mute_data {
        enum ast_frame_type frametype;
        unsigned int direction;
index 04f475b4d44022acd26f5fd73dba0169d86763d8..a50b8720de56cb84f99c8af17e8ac154a8dc9adb 100644 (file)
                                }
                        ]
                },
+               {
+                       "path": "/channels/{channelId}/progress",
+                       "description": "Indicate progress on a channel",
+                       "operations": [
+                               {
+                                       "httpMethod": "POST",
+                                       "since": [
+                                               "22.6.0",
+                                               "21.11.0",
+                                               "20.16.0"
+                                       ],
+                                       "summary": "Indicate progress on a channel.",
+                                       "nickname": "progress",
+                                       "responseClass": "void",
+                                       "parameters": [
+                                               {
+                                                       "name": "channelId",
+                                                       "description": "Channel's id",
+                                                       "paramType": "path",
+                                                       "required": true,
+                                                       "allowMultiple": false,
+                                                       "dataType": "string"
+                                               }
+                                       ],
+                                       "errorResponses": [
+                                               {
+                                                       "code": 404,
+                                                       "reason": "Channel not found"
+                                               },
+                                               {
+                                                       "code": 409,
+                                                       "reason": "Channel not in a Stasis application"
+                                               },
+                                               {
+                                                       "code": 412,
+                                                       "reason": "Channel in invalid state"
+                                               }
+                                       ]
+                               }
+                       ]
+               },
                {
                        "path": "/channels/{channelId}/dtmf",
                        "description": "Send DTMF to a channel",